0
# Parameter Types
1
2
Comprehensive parameter type system enabling custom types with regex patterns, transformation functions, and intelligent matching across all language implementations.
3
4
## Capabilities
5
6
### Built-in Parameter Types
7
8
All Cucumber Expressions implementations provide consistent built-in parameter types for common data types.
9
10
**Numeric Types:**
11
12
```typescript { .api }
13
// Integer types
14
{int} // 32-bit signed integer: matches 42, -19
15
{byte} // 8-bit signed integer: matches -128 to 127
16
{short} // 16-bit signed integer: matches -32768 to 32767
17
{long} // 64-bit signed integer: matches large integers
18
{biginteger} // Arbitrary precision integer: matches any size integer
19
20
// Floating point types
21
{float} // 32-bit floating point: matches 3.6, .8, -9.2
22
{double} // 64-bit floating point: matches high precision decimals
23
{bigdecimal} // Arbitrary precision decimal: matches precise decimals
24
```
25
26
**Text Types:**
27
28
```typescript { .api }
29
{word} // Single word without whitespace: matches "banana"
30
{string} // Quoted strings: matches "banana split", 'hello world'
31
{} // Anonymous type: matches anything
32
```
33
34
**Usage Examples:**
35
36
```typescript
37
import { CucumberExpression, ParameterTypeRegistry } from '@cucumber/cucumber-expressions';
38
39
const registry = new ParameterTypeRegistry();
40
41
// Integer matching
42
const intExpr = new CucumberExpression('I have {int} items', registry);
43
console.log(intExpr.match('I have 42 items')?.[0].getValue()); // 42 (number)
44
console.log(intExpr.match('I have -10 items')?.[0].getValue()); // -10 (number)
45
46
// Float matching
47
const floatExpr = new CucumberExpression('Price is {float} dollars', registry);
48
console.log(floatExpr.match('Price is 29.99 dollars')?.[0].getValue()); // 29.99 (number)
49
console.log(floatExpr.match('Price is .50 dollars')?.[0].getValue()); // 0.5 (number)
50
51
// String matching (removes quotes)
52
const stringExpr = new CucumberExpression('I say {string}', registry);
53
console.log(stringExpr.match('I say "hello world"')?.[0].getValue()); // "hello world"
54
console.log(stringExpr.match("I say 'goodbye'")[0].getValue()); // "goodbye"
55
56
// Word matching (no whitespace)
57
const wordExpr = new CucumberExpression('I like {word}', registry);
58
console.log(wordExpr.match('I like bananas')?.[0].getValue()); // "bananas"
59
console.log(wordExpr.match('I like "banana split"')); // null (contains space)
60
61
// Anonymous matching (anything)
62
const anyExpr = new CucumberExpression('I have {} items', registry);
63
console.log(anyExpr.match('I have many items')?.[0].getValue()); // "many"
64
console.log(anyExpr.match('I have 42 red items')?.[0].getValue()); // "42 red"
65
```
66
67
### Custom Parameter Types
68
69
Define custom parameter types with regex patterns and transformation functions for domain-specific data types.
70
71
**JavaScript/TypeScript:**
72
73
```typescript { .api }
74
class ParameterType<T> {
75
constructor(
76
name: string | undefined,
77
regexps: RegExps,
78
type: Constructor<T> | Factory<T> | null,
79
transform?: (...match: string[]) => T | PromiseLike<T>,
80
useForSnippets?: boolean,
81
preferForRegexpMatch?: boolean,
82
builtin?: boolean
83
);
84
}
85
86
// Helper types
87
type RegExps = readonly (string | RegExp)[] | string | RegExp;
88
type Constructor<T> = new (...args: any[]) => T;
89
type Factory<T> = (...args: any[]) => T;
90
```
91
92
**Usage Examples:**
93
94
```typescript
95
import { ParameterType, ParameterTypeRegistry, CucumberExpression } from '@cucumber/cucumber-expressions';
96
97
// Simple enum-like parameter type
98
const colorType = new ParameterType(
99
'color',
100
/red|green|blue|yellow|purple/,
101
String,
102
(colorName: string) => colorName.toUpperCase()
103
);
104
105
// Complex parameter type with multiple capture groups
106
const dateType = new ParameterType(
107
'date',
108
/(\d{4})-(\d{2})-(\d{2})/,
109
Date,
110
(year: string, month: string, day: string) => {
111
return new Date(parseInt(year), parseInt(month) - 1, parseInt(day));
112
}
113
);
114
115
// Parameter type with object result
116
const coordinateType = new ParameterType(
117
'coordinate',
118
/\((-?\d+),\s*(-?\d+)\)/,
119
Object,
120
(x: string, y: string) => ({ x: parseInt(x), y: parseInt(y) })
121
);
122
123
// Email parameter type with validation
124
const emailType = new ParameterType(
125
'email',
126
/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/,
127
String,
128
(email: string) => {
129
if (!email.includes('@')) {
130
throw new Error('Invalid email format');
131
}
132
return email.toLowerCase();
133
}
134
);
135
136
// Register all types
137
const registry = new ParameterTypeRegistry();
138
registry.defineParameterType(colorType);
139
registry.defineParameterType(dateType);
140
registry.defineParameterType(coordinateType);
141
registry.defineParameterType(emailType);
142
143
// Use in expressions
144
const colorExpr = new CucumberExpression('I have a {color} car', registry);
145
console.log(colorExpr.match('I have a red car')?.[0].getValue()); // "RED"
146
147
const dateExpr = new CucumberExpression('Meeting on {date}', registry);
148
const dateResult = dateExpr.match('Meeting on 2023-12-25')?.[0].getValue();
149
console.log(dateResult instanceof Date); // true
150
console.log(dateResult.getFullYear()); // 2023
151
152
const coordExpr = new CucumberExpression('Move to {coordinate}', registry);
153
console.log(coordExpr.match('Move to (10, -5)')?.[0].getValue()); // { x: 10, y: -5 }
154
155
const emailExpr = new CucumberExpression('Send to {email}', registry);
156
console.log(emailExpr.match('Send to User@Example.COM')?.[0].getValue()); // "user@example.com"
157
```
158
159
**Python:**
160
161
```python { .api }
162
class ParameterType:
163
def __init__(
164
self,
165
name: Optional[str],
166
regexp: Union[List[str], str, List[Pattern], Pattern],
167
type: type,
168
transformer: Optional[Callable] = None,
169
use_for_snippets: bool = True,
170
prefer_for_regexp_match: bool = False
171
): ...
172
```
173
174
**Usage Examples:**
175
176
```python
177
from cucumber_expressions import ParameterType, ParameterTypeRegistry, CucumberExpression
178
import re
179
from datetime import datetime
180
from dataclasses import dataclass
181
182
@dataclass
183
class Point:
184
x: int
185
y: int
186
187
# Custom parameter types
188
color_type = ParameterType(
189
name="color",
190
regexp=r"red|green|blue|yellow",
191
type=str,
192
transformer=lambda s: s.upper()
193
)
194
195
point_type = ParameterType(
196
name="point",
197
regexp=r"\((-?\d+),\s*(-?\d+)\)",
198
type=Point,
199
transformer=lambda x, y: Point(int(x), int(y))
200
)
201
202
date_type = ParameterType(
203
name="iso_date",
204
regexp=r"(\d{4})-(\d{2})-(\d{2})",
205
type=datetime,
206
transformer=lambda year, month, day: datetime(int(year), int(month), int(day))
207
)
208
209
# Register and use
210
registry = ParameterTypeRegistry()
211
registry.define_parameter_type(color_type)
212
registry.define_parameter_type(point_type)
213
registry.define_parameter_type(date_type)
214
215
# Use in expressions
216
color_expr = CucumberExpression("I have a {color} shirt", registry)
217
result = color_expr.match("I have a blue shirt")
218
print(result[0].value) # "BLUE"
219
220
point_expr = CucumberExpression("Move to {point}", registry)
221
result = point_expr.match("Move to (5, -3)")
222
print(result[0].value) # Point(x=5, y=-3)
223
```
224
225
**Java:**
226
227
```java { .api }
228
public final class ParameterType<T> implements Comparable<ParameterType<?>> {
229
public ParameterType(
230
String name,
231
List<String> regexps,
232
Class<T> type,
233
CaptureGroupTransformer<T> transformer
234
);
235
236
public ParameterType(
237
String name,
238
String regexp,
239
Class<T> type,
240
Transformer<T> transformer
241
);
242
243
// Many other constructor overloads available
244
}
245
246
@FunctionalInterface
247
public interface CaptureGroupTransformer<T> {
248
T transform(String[] args) throws Throwable;
249
}
250
251
@FunctionalInterface
252
public interface Transformer<T> {
253
T transform(String arg) throws Throwable;
254
}
255
```
256
257
**Usage Examples:**
258
259
```java
260
import io.cucumber.cucumberexpressions.*;
261
import java.time.LocalDate;
262
import java.util.Arrays;
263
264
// Custom color enum
265
enum Color {
266
RED, GREEN, BLUE, YELLOW;
267
268
public static Color fromString(String s) {
269
return valueOf(s.toUpperCase());
270
}
271
}
272
273
// Color parameter type
274
ParameterType<Color> colorType = new ParameterType<>(
275
"color",
276
"red|green|blue|yellow",
277
Color.class,
278
Color::fromString
279
);
280
281
// Date parameter type with capture groups
282
ParameterType<LocalDate> dateType = new ParameterType<>(
283
"date",
284
Arrays.asList("(\\d{4})-(\\d{2})-(\\d{2})"),
285
LocalDate.class,
286
(String[] args) -> LocalDate.of(
287
Integer.parseInt(args[0]),
288
Integer.parseInt(args[1]),
289
Integer.parseInt(args[2])
290
)
291
);
292
293
// Point class and parameter type
294
class Point {
295
final int x, y;
296
Point(int x, int y) { this.x = x; this.y = y; }
297
public String toString() { return String.format("(%d,%d)", x, y); }
298
}
299
300
ParameterType<Point> pointType = new ParameterType<>(
301
"point",
302
"\\((\\d+),(\\d+)\\)",
303
Point.class,
304
(String[] args) -> new Point(Integer.parseInt(args[0]), Integer.parseInt(args[1]))
305
);
306
307
// Register and use
308
ParameterTypeRegistry registry = new ParameterTypeRegistry();
309
registry.defineParameterType(colorType);
310
registry.defineParameterType(dateType);
311
registry.defineParameterType(pointType);
312
313
CucumberExpression colorExpr = new CucumberExpression("I have a {color} car", registry);
314
List<Argument<?>> colorArgs = colorExpr.match("I have a red car");
315
System.out.println(colorArgs.get(0).getValue()); // RED
316
317
CucumberExpression dateExpr = new CucumberExpression("Meeting on {date}", registry);
318
List<Argument<?>> dateArgs = dateExpr.match("Meeting on 2023-12-25");
319
System.out.println(dateArgs.get(0).getValue()); // 2023-12-25
320
321
CucumberExpression pointExpr = new CucumberExpression("Move to {point}", registry);
322
List<Argument<?>> pointArgs = pointExpr.match("Move to (10,5)");
323
System.out.println(pointArgs.get(0).getValue()); // (10,5)
324
```
325
326
### Parameter Type Configuration
327
328
Control parameter type behavior with configuration options.
329
330
```typescript { .api }
331
// Configuration options for parameter types
332
interface ParameterTypeOptions {
333
/**
334
* Whether to use this parameter type for snippet generation
335
* Default: true
336
*/
337
useForSnippets?: boolean;
338
339
/**
340
* Whether to prefer this parameter type for regexp matches
341
* Default: false
342
*/
343
preferForRegexpMatch?: boolean;
344
345
/**
346
* Whether this is a built-in parameter type
347
* Default: false
348
*/
349
builtin?: boolean;
350
}
351
```
352
353
**Usage Examples:**
354
355
```typescript
356
// Parameter type that won't be used for snippets
357
const internalType = new ParameterType(
358
'internal_id',
359
/INTERNAL_\d+/,
360
String,
361
(s: string) => s,
362
false, // useForSnippets = false
363
false // preferForRegexpMatch = false
364
);
365
366
// Parameter type preferred for regexp matching
367
const preferredType = new ParameterType(
368
'preferred_number',
369
/\d+/,
370
Number,
371
(s: string) => parseInt(s),
372
true, // useForSnippets = true
373
true // preferForRegexpMatch = true
374
);
375
```
376
377
### Parameter Type Registry Management
378
379
Comprehensive registry management with lookup and validation capabilities.
380
381
```typescript { .api }
382
class ParameterTypeRegistry implements DefinesParameterType {
383
/**
384
* Look up parameter type by name
385
*/
386
lookupByTypeName(typeName: string): ParameterType<unknown> | undefined;
387
388
/**
389
* Look up parameter type by regexp pattern
390
*/
391
lookupByRegexp(
392
parameterTypeRegexp: string,
393
expressionRegexp: RegExp,
394
text: string
395
): ParameterType<unknown> | undefined;
396
397
/**
398
* Define new parameter type
399
*/
400
defineParameterType(parameterType: ParameterType<unknown>): void;
401
402
/**
403
* Get all registered parameter types
404
*/
405
readonly parameterTypes: IterableIterator<ParameterType<unknown>>;
406
}
407
```
408
409
**Usage Examples:**
410
411
```typescript
412
const registry = new ParameterTypeRegistry();
413
414
// Check if parameter type exists
415
const intType = registry.lookupByTypeName('int');
416
console.log(intType?.name); // "int"
417
418
// Get all parameter types
419
for (const paramType of registry.parameterTypes) {
420
console.log(`${paramType.name}: ${paramType.regexpStrings}`);
421
}
422
423
// Define custom type and verify
424
const customType = new ParameterType('custom', /custom_\w+/, String);
425
registry.defineParameterType(customType);
426
427
const retrieved = registry.lookupByTypeName('custom');
428
console.log(retrieved === customType); // true
429
```
430
431
### Multi-Language Parameter Type Patterns
432
433
Common patterns for defining parameter types across different programming languages.
434
435
**Enum-based Types:**
436
437
```typescript
438
// TypeScript enum type
439
enum Status { ACTIVE = 'active', INACTIVE = 'inactive', PENDING = 'pending' }
440
441
const statusType = new ParameterType(
442
'status',
443
/active|inactive|pending/,
444
Status,
445
(s: string) => Status[s.toUpperCase() as keyof typeof Status]
446
);
447
```
448
449
```python
450
# Python enum type
451
from enum import Enum
452
453
class Status(Enum):
454
ACTIVE = "active"
455
INACTIVE = "inactive"
456
PENDING = "pending"
457
458
status_type = ParameterType(
459
name="status",
460
regexp=r"active|inactive|pending",
461
type=Status,
462
transformer=lambda s: Status(s.lower())
463
)
464
```
465
466
```java
467
// Java enum type
468
public enum Status {
469
ACTIVE, INACTIVE, PENDING;
470
471
public static Status fromString(String s) {
472
return valueOf(s.toUpperCase());
473
}
474
}
475
476
ParameterType<Status> statusType = new ParameterType<>(
477
"status",
478
"active|inactive|pending",
479
Status.class,
480
Status::fromString
481
);
482
```
483
484
**Complex Object Types:**
485
486
```typescript
487
// TypeScript complex object
488
interface User {
489
name: string;
490
age: number;
491
email: string;
492
}
493
494
const userType = new ParameterType(
495
'user',
496
/(\w+):(\d+):([^:]+)/,
497
Object,
498
(name: string, age: string, email: string): User => ({
499
name,
500
age: parseInt(age),
501
502
})
503
);
504
```
505
506
**Validation and Error Handling:**
507
508
```typescript
509
const validatedEmailType = new ParameterType(
510
'validated_email',
511
/([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/,
512
String,
513
(email: string) => {
514
if (!email.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/)) {
515
throw new Error(`Invalid email format: ${email}`);
516
}
517
return email.toLowerCase();
518
}
519
);
520
```
521
522
## Advanced Parameter Type Features
523
524
### Async Transformers
525
526
Support for asynchronous transformation functions in JavaScript/TypeScript.
527
528
```typescript { .api }
529
// Async transformer example
530
const asyncUserType = new ParameterType(
531
'async_user',
532
/user_(\d+)/,
533
Object,
534
async (userId: string) => {
535
// Simulate async database lookup
536
const response = await fetch(`/api/users/${userId}`);
537
return await response.json();
538
}
539
);
540
541
// Usage with async/await
542
const expr = new CucumberExpression('Load {async_user}', registry);
543
const args = expr.match('Load user_123');
544
if (args) {
545
const user = await args[0].getValue();
546
console.log(user); // User object from API
547
}
548
```
549
550
### Multiple Regex Patterns
551
552
Support for multiple regex patterns per parameter type.
553
554
```typescript { .api }
555
// Multiple pattern support
556
const flexibleDateType = new ParameterType(
557
'flexible_date',
558
[
559
/(\d{4})-(\d{2})-(\d{2})/, // ISO format: 2023-12-25
560
/(\d{2})\/(\d{2})\/(\d{4})/, // US format: 12/25/2023
561
/(\d{2})-(\d{2})-(\d{4})/ // EU format: 25-12-2023
562
],
563
Date,
564
(...parts: string[]) => {
565
// Handle different date formats
566
if (parts[0].length === 4) {
567
// ISO format: YYYY-MM-DD
568
return new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2]));
569
} else if (parts[2].length === 4) {
570
// US or EU format based on position
571
return new Date(parseInt(parts[2]), parseInt(parts[0]) - 1, parseInt(parts[1]));
572
}
573
throw new Error('Invalid date format');
574
}
575
);
576
```
577
578
Built-in parameter types provide comprehensive coverage for common data types, while custom parameter types enable domain-specific extensions with full transformation and validation capabilities across all supported programming languages.