0
# JavaScript/TypeScript Implementation
1
2
Complete TypeScript implementation with full type safety, dual package support (ESM/CJS), and comprehensive API coverage for browser and Node.js environments.
3
4
## Package Information
5
6
- **Package Name**: `@cucumber/cucumber-expressions`
7
- **Language**: TypeScript/JavaScript
8
- **Installation**: `npm install @cucumber/cucumber-expressions`
9
- **Entry Points**: ESM (`dist/esm/src/index.js`), CJS (`dist/cjs/src/index.js`)
10
- **Type Definitions**: `dist/cjs/src/index.d.ts`
11
12
## Core Imports
13
14
```typescript
15
import {
16
CucumberExpression,
17
ParameterType,
18
ParameterTypeRegistry,
19
ExpressionFactory,
20
CucumberExpressionGenerator,
21
Argument,
22
GeneratedExpression,
23
RegularExpression
24
} from '@cucumber/cucumber-expressions';
25
```
26
27
For CommonJS environments:
28
29
```javascript
30
const {
31
CucumberExpression,
32
ParameterTypeRegistry,
33
ExpressionFactory
34
} = require('@cucumber/cucumber-expressions');
35
```
36
37
## Capabilities
38
39
### Expression Creation and Matching
40
41
Create and match Cucumber expressions with full type safety and parameter extraction.
42
43
```typescript { .api }
44
/**
45
* Main class for parsing and matching Cucumber expressions
46
*/
47
class CucumberExpression implements Expression {
48
/**
49
* Create a new Cucumber expression
50
* @param expression - The Cucumber expression string
51
* @param parameterTypeRegistry - Registry containing parameter types
52
*/
53
constructor(expression: string, parameterTypeRegistry: ParameterTypeRegistry);
54
55
/**
56
* Match text against this expression and extract arguments
57
* @param text - Text to match against the expression
58
* @returns Array of matched arguments or null if no match
59
*/
60
match(text: string): readonly Argument[] | null;
61
62
/** The original expression string */
63
readonly source: string;
64
65
/** The compiled regular expression */
66
readonly regexp: RegExp;
67
68
/** The abstract syntax tree representation */
69
readonly ast: Node;
70
}
71
72
/**
73
* Common interface for all expression types
74
*/
75
interface Expression {
76
/** The original expression string */
77
readonly source: string;
78
79
/**
80
* Match text against this expression
81
* @param text - Text to match
82
* @returns Array of matched arguments or null if no match
83
*/
84
match(text: string): readonly Argument[] | null;
85
}
86
```
87
88
**Usage Examples:**
89
90
```typescript
91
import { CucumberExpression, ParameterTypeRegistry } from '@cucumber/cucumber-expressions';
92
93
// Create registry with built-in parameter types
94
const registry = new ParameterTypeRegistry();
95
96
// Simple integer parameter
97
const expr1 = new CucumberExpression('I have {int} cucumbers', registry);
98
const args1 = expr1.match('I have 42 cucumbers');
99
console.log(args1?.[0].getValue()); // 42 (number)
100
101
// Multiple parameters
102
const expr2 = new CucumberExpression('I have {int} {word} and {float} {word}', registry);
103
const args2 = expr2.match('I have 42 cucumbers and 3.5 apples');
104
console.log(args2?.[0].getValue()); // 42 (number)
105
console.log(args2?.[1].getValue()); // "cucumbers" (string)
106
console.log(args2?.[2].getValue()); // 3.5 (number)
107
console.log(args2?.[3].getValue()); // "apples" (string)
108
109
// Optional text
110
const expr3 = new CucumberExpression('I have {int} cucumber(s)', registry);
111
console.log(expr3.match('I have 1 cucumber')); // matches
112
console.log(expr3.match('I have 5 cucumbers')); // matches
113
114
// Alternative text
115
const expr4 = new CucumberExpression('I put it in my belly/stomach', registry);
116
console.log(expr4.match('I put it in my belly')); // matches
117
console.log(expr4.match('I put it in my stomach')); // matches
118
```
119
120
### Parameter Type Definition
121
122
Define custom parameter types with regex patterns and transformation functions.
123
124
```typescript { .api }
125
/**
126
* Defines a parameter type with name, patterns, and transformer
127
*/
128
class ParameterType<T> {
129
/**
130
* Create a new parameter type
131
* @param name - Name used in expressions (e.g., 'color' for {color})
132
* @param regexps - Regular expression patterns to match
133
* @param type - Constructor or factory for the result type
134
* @param transform - Function to transform matched strings to result type
135
* @param useForSnippets - Whether to use this type for snippet generation
136
* @param preferForRegexpMatch - Whether to prefer this type in regexp matches
137
* @param builtin - Whether this is a built-in parameter type
138
*/
139
constructor(
140
name: string | undefined,
141
regexps: RegExps,
142
type: Constructor<T> | Factory<T> | null,
143
transform?: (...match: string[]) => T | PromiseLike<T>,
144
useForSnippets?: boolean,
145
preferForRegexpMatch?: boolean,
146
builtin?: boolean
147
);
148
149
/**
150
* Compare two parameter types for sorting
151
*/
152
static compare(pt1: ParameterType<unknown>, pt2: ParameterType<unknown>): number;
153
154
/**
155
* Check if a parameter type name is valid
156
*/
157
static checkParameterTypeName(typeName: string): void;
158
159
/**
160
* Test if a parameter type name is valid
161
*/
162
static isValidParameterTypeName(typeName: string): boolean;
163
164
/** The parameter type name */
165
readonly name: string | undefined;
166
167
/** The type constructor or factory */
168
readonly type: Constructor<T> | Factory<T> | null;
169
170
/** Whether to use for snippet generation */
171
readonly useForSnippets: boolean;
172
173
/** Whether to prefer for regexp matching */
174
readonly preferForRegexpMatch: boolean;
175
176
/** Whether this is a built-in type */
177
readonly builtin: boolean;
178
179
/** The regular expression strings */
180
readonly regexpStrings: readonly string[];
181
182
/**
183
* Transform matched groups to the target type
184
* @param thisObj - Context object for transformation
185
* @param groupValues - Matched string groups
186
* @returns Transformed value
187
*/
188
transform(thisObj: unknown, groupValues: string[] | null): T;
189
}
190
191
/**
192
* Type definitions for parameter type construction
193
*/
194
type RegExps = readonly (string | RegExp)[] | string | RegExp;
195
type Constructor<T> = new (...args: any[]) => T;
196
type Factory<T> = (...args: any[]) => T;
197
```
198
199
**Usage Examples:**
200
201
```typescript
202
import { ParameterType, ParameterTypeRegistry } from '@cucumber/cucumber-expressions';
203
204
// Custom color parameter type
205
const colorType = new ParameterType(
206
'color',
207
/red|green|blue|yellow/,
208
String,
209
(s: string) => s.toUpperCase(),
210
true,
211
false
212
);
213
214
const registry = new ParameterTypeRegistry();
215
registry.defineParameterType(colorType);
216
217
// Use in expression
218
const expr = new CucumberExpression('I have a {color} ball', registry);
219
const args = expr.match('I have a red ball');
220
console.log(args?.[0].getValue()); // "RED"
221
222
// Custom type with capture groups
223
const coordinateType = new ParameterType(
224
'coordinate',
225
/(-?\d+),(-?\d+)/,
226
Object,
227
(x: string, y: string) => ({ x: parseInt(x), y: parseInt(y) }),
228
true,
229
false
230
);
231
232
registry.defineParameterType(coordinateType);
233
234
const coordExpr = new CucumberExpression('I am at {coordinate}', registry);
235
const coordArgs = coordExpr.match('I am at 10,-5');
236
console.log(coordArgs?.[0].getValue()); // { x: 10, y: -5 }
237
```
238
239
### Parameter Type Registry
240
241
Central registry for managing parameter types with lookup and definition capabilities.
242
243
```typescript { .api }
244
/**
245
* Registry for managing parameter types
246
*/
247
class ParameterTypeRegistry implements DefinesParameterType {
248
/**
249
* Create a new parameter type registry with built-in types
250
*/
251
constructor();
252
253
/** Iterator over all registered parameter types */
254
readonly parameterTypes: IterableIterator<ParameterType<unknown>>;
255
256
/**
257
* Look up a parameter type by name
258
* @param typeName - Name of the parameter type
259
* @returns Parameter type or undefined if not found
260
*/
261
lookupByTypeName(typeName: string): ParameterType<unknown> | undefined;
262
263
/**
264
* Look up parameter type by regular expression pattern
265
* @param parameterTypeRegexp - Regular expression to match
266
* @param expressionRegexp - Full expression regexp
267
* @param text - Text being matched
268
* @returns Matching parameter type or undefined
269
*/
270
lookupByRegexp(
271
parameterTypeRegexp: string,
272
expressionRegexp: RegExp,
273
text: string
274
): ParameterType<unknown> | undefined;
275
276
/**
277
* Register a new parameter type
278
* @param parameterType - Parameter type to register
279
*/
280
defineParameterType(parameterType: ParameterType<unknown>): void;
281
}
282
283
/**
284
* Interface for objects that can define parameter types
285
*/
286
interface DefinesParameterType {
287
defineParameterType<T>(parameterType: ParameterType<T>): void;
288
}
289
```
290
291
### Expression Factory
292
293
Factory for creating expressions from strings or regular expressions.
294
295
```typescript { .api }
296
/**
297
* Factory for creating expressions
298
*/
299
class ExpressionFactory {
300
/**
301
* Create expression factory with parameter type registry
302
* @param parameterTypeRegistry - Registry for parameter types
303
*/
304
constructor(parameterTypeRegistry: ParameterTypeRegistry);
305
306
/**
307
* Create an expression from string or RegExp
308
* @param expression - Expression string or regular expression
309
* @returns Expression instance (CucumberExpression or RegularExpression)
310
*/
311
createExpression(expression: string | RegExp): Expression;
312
}
313
```
314
315
**Usage Examples:**
316
317
```typescript
318
import { ExpressionFactory, ParameterTypeRegistry } from '@cucumber/cucumber-expressions';
319
320
const registry = new ParameterTypeRegistry();
321
const factory = new ExpressionFactory(registry);
322
323
// Create Cucumber expression
324
const cucumberExpr = factory.createExpression('I have {int} cucumbers');
325
console.log(cucumberExpr instanceof CucumberExpression); // true
326
327
// Create regular expression
328
const regexExpr = factory.createExpression(/^I have (\d+) cucumbers$/);
329
console.log(regexExpr instanceof RegularExpression); // true
330
```
331
332
### Expression Generation
333
334
Generate Cucumber expressions from example text for automated step definition creation.
335
336
```typescript { .api }
337
/**
338
* Generates Cucumber expressions from example text
339
*/
340
class CucumberExpressionGenerator {
341
/**
342
* Create generator with parameter types
343
* @param parameterTypes - Function returning iterable of parameter types
344
*/
345
constructor(parameterTypes: () => Iterable<ParameterType<unknown>>);
346
347
/**
348
* Generate expressions from example text
349
* @param text - Example text to generate expressions from
350
* @returns Array of generated expressions
351
*/
352
generateExpressions(text: string): readonly GeneratedExpression[];
353
}
354
355
/**
356
* Generated expression with metadata
357
*/
358
class GeneratedExpression {
359
/**
360
* Create generated expression
361
* @param expressionTemplate - Template string with parameter placeholders
362
* @param parameterTypes - Array of parameter types in order
363
*/
364
constructor(
365
expressionTemplate: string,
366
parameterTypes: readonly ParameterType<unknown>[]
367
);
368
369
/** The generated expression source */
370
readonly source: string;
371
372
/** Parameter names in order */
373
readonly parameterNames: readonly string[];
374
375
/** Parameter information */
376
readonly parameterInfos: readonly ParameterInfo[];
377
378
/** Parameter types in order */
379
readonly parameterTypes: readonly ParameterType<unknown>[];
380
}
381
382
/**
383
* Parameter information for code generation
384
*/
385
interface ParameterInfo {
386
/** Parameter type name */
387
type: string | null;
388
/** Parameter name for code generation */
389
name: string;
390
/** Number of occurrences */
391
count: number;
392
}
393
```
394
395
**Usage Examples:**
396
397
```typescript
398
import { CucumberExpressionGenerator, ParameterTypeRegistry } from '@cucumber/cucumber-expressions';
399
400
const registry = new ParameterTypeRegistry();
401
const generator = new CucumberExpressionGenerator(() => registry.parameterTypes);
402
403
// Generate from text with numbers
404
const expressions1 = generator.generateExpressions('I have 42 cucumbers');
405
console.log(expressions1[0].source); // "I have {int} cucumbers"
406
407
// Generate from text with quoted strings
408
const expressions2 = generator.generateExpressions('I have "many" cucumbers');
409
console.log(expressions2[0].source); // "I have {string} cucumbers"
410
411
// Generate from complex text
412
const expressions3 = generator.generateExpressions('User john has 5 apples and 3.5 oranges');
413
expressions3.forEach(expr => {
414
console.log(expr.source);
415
console.log(expr.parameterTypes.map(pt => pt.name));
416
});
417
```
418
419
### Argument Extraction
420
421
Extract and transform matched arguments from expressions.
422
423
```typescript { .api }
424
/**
425
* Represents a matched argument from an expression
426
*/
427
class Argument {
428
/**
429
* Create argument with group and parameter type
430
* @param group - Matched group from regex
431
* @param parameterType - Parameter type for transformation
432
*/
433
constructor(group: Group, parameterType: ParameterType<unknown>);
434
435
/**
436
* Build arguments from matched groups
437
* @param group - Root group from match
438
* @param parameterTypes - Parameter types for transformation
439
* @returns Array of arguments
440
*/
441
static build(group: Group, parameterTypes: readonly ParameterType<unknown>[]): readonly Argument[];
442
443
/** The matched group */
444
readonly group: Group;
445
446
/** The parameter type */
447
readonly parameterType: ParameterType<unknown>;
448
449
/**
450
* Get the transformed value
451
* @param thisObj - Context object for transformation
452
* @returns Transformed value or null
453
*/
454
getValue<T>(thisObj: unknown): T | null;
455
456
/**
457
* Get the parameter type
458
* @returns Parameter type
459
*/
460
getParameterType(): ParameterType<unknown>;
461
}
462
463
/**
464
* Represents a matched group from regex matching
465
*/
466
interface Group {
467
/** Matched text value */
468
value: string | null;
469
/** Start position in source text */
470
start: number;
471
/** End position in source text */
472
end: number;
473
/** Child groups */
474
children: Group[];
475
}
476
```
477
478
### Regular Expression Support
479
480
Support for traditional regular expressions alongside Cucumber expressions.
481
482
```typescript { .api }
483
/**
484
* Regular expression implementation of Expression interface
485
*/
486
class RegularExpression implements Expression {
487
/**
488
* Create regular expression
489
* @param regexp - Regular expression pattern
490
* @param parameterTypeRegistry - Registry for parameter types
491
*/
492
constructor(regexp: RegExp, parameterTypeRegistry: ParameterTypeRegistry);
493
494
/** The regular expression */
495
readonly regexp: RegExp;
496
497
/** The source pattern */
498
readonly source: string;
499
500
/**
501
* Match text against regular expression
502
* @param text - Text to match
503
* @returns Array of arguments or null if no match
504
*/
505
match(text: string): readonly Argument[] | null;
506
}
507
```
508
509
## AST Support
510
511
Abstract Syntax Tree representation for advanced expression manipulation.
512
513
```typescript { .api }
514
/**
515
* AST node representing parsed expression components
516
*/
517
interface Node {
518
/** Node type identifier */
519
type: NodeType;
520
/** Child nodes */
521
nodes?: Node[];
522
/** Associated token */
523
token?: Token;
524
/** Get text representation */
525
text(): string;
526
}
527
528
/**
529
* Token from lexical analysis
530
*/
531
interface Token {
532
/** Token type */
533
type: TokenType;
534
/** Token text */
535
text: string;
536
/** Start position */
537
start: number;
538
/** End position */
539
end: number;
540
}
541
542
/**
543
* AST node types
544
*/
545
enum NodeType {
546
text = 'text',
547
optional = 'optional',
548
alternation = 'alternation',
549
alternative = 'alternative',
550
parameter = 'parameter',
551
expression = 'expression'
552
}
553
554
/**
555
* Token types from lexer
556
*/
557
enum TokenType {
558
START_OF_LINE = 'START_OF_LINE',
559
END_OF_LINE = 'END_OF_LINE',
560
WHITE_SPACE = 'WHITE_SPACE',
561
BEGIN_PARAMETER = 'BEGIN_PARAMETER',
562
END_PARAMETER = 'END_PARAMETER',
563
BEGIN_OPTIONAL = 'BEGIN_OPTIONAL',
564
END_OPTIONAL = 'END_OPTIONAL',
565
BEGIN_ALTERNATION = 'BEGIN_ALTERNATION',
566
END_ALTERNATION = 'END_ALTERNATION',
567
ALTERNATION_PIPE = 'ALTERNATION_PIPE',
568
TEXT = 'TEXT'
569
}
570
```
571
572
## Built-in Parameter Types
573
574
The JavaScript/TypeScript implementation includes comprehensive built-in parameter types:
575
576
- `{int}` - 32-bit signed integers
577
- `{float}` - 32-bit floating point numbers
578
- `{word}` - Single words without whitespace
579
- `{string}` - Quoted strings (single or double quotes)
580
- `{bigdecimal}` - High-precision decimal numbers
581
- `{double}` - 64-bit floating point numbers
582
- `{biginteger}` - Arbitrary precision integers
583
- `{byte}` - 8-bit signed integers
584
- `{short}` - 16-bit signed integers
585
- `{long}` - 64-bit signed integers
586
- `{}` (anonymous) - Matches any text
587
588
All built-in types support appropriate JavaScript type conversion and error handling.