or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

dotnet.mdexpression-factory.mdgo.mdindex.mdjava.mdjavascript-typescript.mdparameter-types.mdpython.mdruby.md

expression-factory.mddocs/

0

# Expression Factory and Generation

1

2

Factory pattern for creating expressions and advanced expression generation from example text, enabling automated step definition creation and flexible expression management.

3

4

## Capabilities

5

6

### Expression Factory

7

8

Create expressions from strings or regular expressions with automatic type detection and proper configuration.

9

10

```typescript { .api }

11

/**

12

* Factory for creating expressions with automatic type detection

13

*/

14

class ExpressionFactory {

15

/**

16

* Create expression factory with parameter type registry

17

* @param parameterTypeRegistry - Registry containing parameter types

18

*/

19

constructor(parameterTypeRegistry: ParameterTypeRegistry);

20

21

/**

22

* Create expression from string or RegExp with automatic type detection

23

* @param expression - Cucumber expression string or regular expression

24

* @returns CucumberExpression for strings, RegularExpression for RegExp objects

25

*/

26

createExpression(expression: string | RegExp): Expression;

27

}

28

```

29

30

**Usage Examples:**

31

32

```typescript

33

import { ExpressionFactory, ParameterTypeRegistry, CucumberExpression, RegularExpression } from '@cucumber/cucumber-expressions';

34

35

const registry = new ParameterTypeRegistry();

36

const factory = new ExpressionFactory(registry);

37

38

// Create Cucumber expression from string

39

const cucumberExpr = factory.createExpression('I have {int} cucumbers');

40

console.log(cucumberExpr instanceof CucumberExpression); // true

41

console.log(cucumberExpr.source); // "I have {int} cucumbers"

42

43

// Create regular expression from RegExp

44

const regexExpr = factory.createExpression(/^I have (\d+) cucumbers$/);

45

console.log(regexExpr instanceof RegularExpression); // true

46

console.log(regexExpr.regexp.source); // "^I have (\\d+) cucumbers$"

47

48

// Auto-detection of regular expression patterns

49

const anchoredExpr = factory.createExpression('^I have (\\d+) items$');

50

console.log(anchoredExpr instanceof RegularExpression); // true

51

52

const slashExpr = factory.createExpression('/I have (\\d+) items/');

53

console.log(slashExpr instanceof RegularExpression); // true

54

55

// Use expressions for matching

56

const text = 'I have 42 cucumbers';

57

const cucumberArgs = cucumberExpr.match(text);

58

const regexArgs = regexExpr.match(text);

59

60

console.log(cucumberArgs?.[0].getValue()); // 42 (typed as number)

61

console.log(regexArgs?.[0].getValue()); // "42" (as string)

62

```

63

64

**Python Implementation:**

65

66

```python { .api }

67

# Python expression factory pattern (manual implementation)

68

from cucumber_expressions import CucumberExpression, RegularExpression, ParameterTypeRegistry

69

import re

70

71

class ExpressionFactory:

72

def __init__(self, parameter_type_registry: ParameterTypeRegistry):

73

self.parameter_type_registry = parameter_type_registry

74

75

def create_expression(self, expression_string: str):

76

"""Create expression with automatic type detection"""

77

if self._is_regular_expression(expression_string):

78

pattern = self._extract_regex_pattern(expression_string)

79

return RegularExpression(re.compile(pattern), self.parameter_type_registry)

80

else:

81

return CucumberExpression(expression_string, self.parameter_type_registry)

82

83

def _is_regular_expression(self, expression: str) -> bool:

84

return (expression.startswith('^') and expression.endswith('$')) or \

85

(expression.startswith('/') and expression.endswith('/'))

86

87

def _extract_regex_pattern(self, expression: str) -> str:

88

if expression.startswith('/') and expression.endswith('/'):

89

return expression[1:-1]

90

return expression

91

```

92

93

**Java Implementation:**

94

95

```java { .api }

96

/**

97

* Factory for creating expressions with automatic type detection

98

*/

99

public final class ExpressionFactory {

100

/**

101

* Create expression factory with parameter type registry

102

* @param parameterTypeRegistry Registry for parameter types

103

*/

104

public ExpressionFactory(ParameterTypeRegistry parameterTypeRegistry);

105

106

/**

107

* Create expression from string with automatic type detection

108

* @param expressionString Expression string (Cucumber or regex pattern)

109

* @return Expression instance

110

*/

111

public Expression createExpression(String expressionString);

112

113

/**

114

* Create expression from Pattern

115

* @param pattern Regular expression pattern

116

* @return RegularExpression instance

117

*/

118

public Expression createExpression(Pattern pattern);

119

}

120

```

121

122

**Usage Examples:**

123

124

```java

125

import io.cucumber.cucumberexpressions.*;

126

import java.util.regex.Pattern;

127

128

ParameterTypeRegistry registry = new ParameterTypeRegistry();

129

ExpressionFactory factory = new ExpressionFactory(registry);

130

131

// Cucumber expression

132

Expression cucumberExpr = factory.createExpression("I have {int} items");

133

System.out.println(cucumberExpr.getClass().getSimpleName()); // "CucumberExpression"

134

135

// Regular expression with anchors

136

Expression regexExpr = factory.createExpression("^I have (\\d+) items$");

137

System.out.println(regexExpr.getClass().getSimpleName()); // "RegularExpression"

138

139

// Regular expression from Pattern

140

Pattern pattern = Pattern.compile("^Count: (\\d+)$");

141

Expression patternExpr = factory.createExpression(pattern);

142

System.out.println(patternExpr.getClass().getSimpleName()); // "RegularExpression"

143

```

144

145

### Expression Generation

146

147

Generate Cucumber expressions from example text for automated step definition creation and IDE tooling.

148

149

```typescript { .api }

150

/**

151

* Generates Cucumber expressions from example text

152

*/

153

class CucumberExpressionGenerator {

154

/**

155

* Create generator with parameter types supplier

156

* @param parameterTypes Function returning iterable of available parameter types

157

*/

158

constructor(parameterTypes: () => Iterable<ParameterType<unknown>>);

159

160

/**

161

* Generate expressions from example text

162

* @param text Example text to analyze and generate expressions from

163

* @returns Array of generated expressions ranked by specificity

164

*/

165

generateExpressions(text: string): readonly GeneratedExpression[];

166

}

167

168

/**

169

* Generated expression result with metadata

170

*/

171

class GeneratedExpression {

172

/**

173

* Create generated expression

174

* @param expressionTemplate Template with parameter placeholders

175

* @param parameterTypes Parameter types used in expression

176

*/

177

constructor(

178

expressionTemplate: string,

179

parameterTypes: readonly ParameterType<unknown>[]

180

);

181

182

/** The generated Cucumber expression */

183

readonly source: string;

184

185

/** Parameter names for code generation */

186

readonly parameterNames: readonly string[];

187

188

/** Parameter information for IDE integration */

189

readonly parameterInfos: readonly ParameterInfo[];

190

191

/** Parameter types in declaration order */

192

readonly parameterTypes: readonly ParameterType<unknown>[];

193

}

194

195

/**

196

* Parameter metadata for code generation

197

*/

198

interface ParameterInfo {

199

/** Parameter type name for code generation */

200

type: string | null;

201

/** Suggested parameter name */

202

name: string;

203

/** Number of occurrences in expression */

204

count: number;

205

}

206

```

207

208

**Usage Examples:**

209

210

```typescript

211

import { CucumberExpressionGenerator, ParameterTypeRegistry } from '@cucumber/cucumber-expressions';

212

213

const registry = new ParameterTypeRegistry();

214

const generator = new CucumberExpressionGenerator(() => registry.parameterTypes);

215

216

// Generate from text with integers

217

const expressions1 = generator.generateExpressions('I have 42 cucumbers');

218

console.log(expressions1.length); // Multiple alternatives

219

console.log(expressions1[0].source); // "I have {int} cucumbers"

220

console.log(expressions1[0].parameterNames); // ["int"]

221

console.log(expressions1[0].parameterInfos[0]); // { type: "int", name: "int", count: 1 }

222

223

// Generate from text with multiple parameters

224

const expressions2 = generator.generateExpressions('User john has 5 apples and 3.5 oranges');

225

expressions2.forEach((expr, index) => {

226

console.log(`Option ${index + 1}: ${expr.source}`);

227

console.log(`Parameters: ${expr.parameterTypes.map(pt => pt.name).join(', ')}`);

228

});

229

// Output might include:

230

// "User {word} has {int} {word} and {float} {word}"

231

// "User {word} has {int} apples and {float} oranges"

232

233

// Generate from text with quoted strings

234

const expressions3 = generator.generateExpressions('I select "Premium Plan" option');

235

console.log(expressions3[0].source); // "I select {string} option"

236

console.log(expressions3[0].parameterNames); // ["string"]

237

238

// Generate from complex scenarios

239

const expressions4 = generator.generateExpressions('On 2023-12-25 at 14:30, send email to user@example.com');

240

expressions4.forEach(expr => {

241

console.log(expr.source);

242

// Might generate expressions for dates, times, emails if custom types are registered

243

});

244

```

245

246

**Python Implementation:**

247

248

```python { .api }

249

class CucumberExpressionGenerator:

250

def __init__(self, parameter_type_registry: ParameterTypeRegistry):

251

"""Create generator with parameter type registry"""

252

self.parameter_type_registry = parameter_type_registry

253

254

def generate_expressions(self, text: str) -> List[GeneratedExpression]:

255

"""Generate expressions from example text"""

256

...

257

258

@staticmethod

259

def escape(string: str) -> str:

260

"""Escape special regex characters in string"""

261

...

262

263

class GeneratedExpression:

264

def __init__(self, expression_template: str, parameter_types: List[ParameterType]):

265

self.source = expression_template

266

self.parameter_types = parameter_types

267

self.parameter_names = [pt.name for pt in parameter_types]

268

```

269

270

**Usage Examples:**

271

272

```python

273

from cucumber_expressions import CucumberExpressionGenerator, ParameterTypeRegistry

274

275

registry = ParameterTypeRegistry()

276

generator = CucumberExpressionGenerator(registry)

277

278

# Generate from example text

279

expressions = generator.generate_expressions("I have 42 items")

280

for expr in expressions:

281

print(f"Expression: {expr.source}")

282

print(f"Parameters: {[pt.name for pt in expr.parameter_types]}")

283

284

# Generate with custom parameter types

285

from cucumber_expressions import ParameterType

286

287

color_type = ParameterType(

288

name="color",

289

regexp=r"red|green|blue",

290

type=str,

291

transformer=str.upper

292

)

293

registry.define_parameter_type(color_type)

294

295

expressions = generator.generate_expressions("I have a red car")

296

print(expressions[0].source) # Might be "I have a {color} car" if color is detected

297

```

298

299

**Java Implementation:**

300

301

```java { .api }

302

/**

303

* Generates Cucumber expressions from example text

304

*/

305

public final class CucumberExpressionGenerator {

306

/**

307

* Create generator with parameter type registry

308

* @param parameterTypeRegistry Registry containing available parameter types

309

*/

310

public CucumberExpressionGenerator(ParameterTypeRegistry parameterTypeRegistry);

311

312

/**

313

* Generate expressions from example text

314

* @param text Example text to analyze

315

* @return List of generated expressions

316

*/

317

public List<GeneratedExpression> generateExpressions(String text);

318

}

319

320

/**

321

* Generated expression with metadata

322

*/

323

public final class GeneratedExpression {

324

/**

325

* Create generated expression

326

* @param expressionTemplate Template string with parameters

327

* @param parameterTypes List of parameter types

328

*/

329

public GeneratedExpression(String expressionTemplate, List<ParameterType<?>> parameterTypes);

330

331

/** Get the generated expression source */

332

public String getSource();

333

334

/** Get parameter names for code generation */

335

public List<String> getParameterNames();

336

337

/** Get parameter information */

338

public List<ParameterInfo> getParameterInfos();

339

340

/** Get parameter types */

341

public List<ParameterType<?>> getParameterTypes();

342

}

343

344

/**

345

* Parameter information for code generation

346

*/

347

public final class ParameterInfo {

348

/** Parameter type name */

349

public String getType();

350

351

/** Suggested parameter name */

352

public String getName();

353

354

/** Parameter occurrence count */

355

public int getCount();

356

}

357

```

358

359

**Usage Examples:**

360

361

```java

362

import io.cucumber.cucumberexpressions.*;

363

import java.util.List;

364

365

ParameterTypeRegistry registry = new ParameterTypeRegistry();

366

CucumberExpressionGenerator generator = new CucumberExpressionGenerator(registry);

367

368

// Generate from simple text

369

List<GeneratedExpression> expressions = generator.generateExpressions("I have 42 items");

370

GeneratedExpression first = expressions.get(0);

371

System.out.println("Expression: " + first.getSource()); // "I have {int} items"

372

System.out.println("Parameter count: " + first.getParameterTypes().size()); // 1

373

374

// Generate method signatures for step definitions

375

for (ParameterInfo info : first.getParameterInfos()) {

376

System.out.printf("Parameter: %s %s%n", info.getType(), info.getName());

377

}

378

379

// Generate from complex text

380

List<GeneratedExpression> complex = generator.generateExpressions(

381

"User alice with age 25 has balance 123.45"

382

);

383

for (GeneratedExpression expr : complex) {

384

System.out.println("Generated: " + expr.getSource());

385

// Might output: "User {word} with age {int} has balance {float}"

386

}

387

```

388

389

### Expression Ranking and Selection

390

391

Generated expressions are ranked by specificity and usefulness for step definition creation.

392

393

```typescript { .api }

394

// Expression ranking factors:

395

// 1. More specific parameter types rank higher

396

// 2. Fewer anonymous parameters rank higher

397

// 3. More captured parameters rank higher

398

// 4. Built-in types preferred over custom types

399

```

400

401

**Usage Examples:**

402

403

```typescript

404

const expressions = generator.generateExpressions('Order #12345 costs $29.99');

405

406

// Results might be ranked as:

407

// 1. "Order #{int} costs ${float}" (most specific)

408

// 2. "Order #{word} costs ${float}" (less specific number)

409

// 3. "Order {} costs ${float}" (anonymous number)

410

// 4. "Order {} costs {}" (least specific)

411

412

console.log('Best match:', expressions[0].source);

413

console.log('Alternatives:');

414

expressions.slice(1).forEach((expr, index) => {

415

console.log(` ${index + 2}. ${expr.source}`);

416

});

417

```

418

419

### IDE Integration Support

420

421

Generated expressions provide metadata for IDE integration and code generation.

422

423

```typescript { .api }

424

// Code generation helpers

425

interface GeneratedExpression {

426

/** Generate method signature for step definition */

427

generateMethodSignature(language: 'typescript' | 'java' | 'python'): string;

428

429

/** Generate step definition template */

430

generateStepDefinition(language: 'typescript' | 'java' | 'python'): string;

431

}

432

```

433

434

**Usage Examples:**

435

436

```typescript

437

const expressions = generator.generateExpressions('User john has 5 items');

438

const best = expressions[0];

439

440

// TypeScript step definition generation

441

console.log('TypeScript:');

442

console.log(`Given('${best.source}', (${best.parameterNames.map((name, i) =>

443

`${name}: ${getTypeName(best.parameterTypes[i])}`

444

).join(', ')}) => {`);

445

console.log(' // Implementation here');

446

console.log('});');

447

448

// Java step definition generation

449

console.log('\nJava:');

450

console.log(`@Given("${best.source}")`);

451

console.log(`public void userHasItems(${best.parameterTypes.map((type, i) =>

452

`${getJavaType(type)} ${best.parameterNames[i]}`

453

).join(', ')}) {`);

454

console.log(' // Implementation here');

455

console.log('}');

456

457

function getTypeName(paramType: ParameterType<unknown>): string {

458

switch (paramType.name) {

459

case 'int': return 'number';

460

case 'float': return 'number';

461

case 'string': return 'string';

462

case 'word': return 'string';

463

default: return 'unknown';

464

}

465

}

466

467

function getJavaType(paramType: ParameterType<unknown>): string {

468

switch (paramType.name) {

469

case 'int': return 'Integer';

470

case 'float': return 'Float';

471

case 'string': return 'String';

472

case 'word': return 'String';

473

default: return 'Object';

474

}

475

}

476

```

477

478

### Advanced Generation Features

479

480

Support for complex text patterns and custom parameter type recognition.

481

482

```typescript { .api }

483

// Advanced generation with custom types

484

const emailType = new ParameterType('email', /[^@]+@[^.]+\..+/, String);

485

const dateType = new ParameterType('date', /\d{4}-\d{2}-\d{2}/, String);

486

487

registry.defineParameterType(emailType);

488

registry.defineParameterType(dateType);

489

490

const expressions = generator.generateExpressions(

491

'Send reminder to john@example.com on 2023-12-25'

492

);

493

494

console.log(expressions[0].source);

495

// "Send reminder to {email} on {date}"

496

```

497

498

**Escaping and Special Characters:**

499

500

```typescript

501

// Handle special characters in generated expressions

502

const textWithSpecialChars = 'File path is C:\\Program Files\\App (x86)';

503

const expressions = generator.generateExpressions(textWithSpecialChars);

504

505

// Generator automatically escapes special regex characters

506

console.log(expressions[0].source);

507

// "File path is C:\\\\Program Files\\\\App \\(x86\\)"

508

```

509

510

**Multi-Language Consistency:**

511

512

All language implementations provide consistent expression generation with the same ranking algorithms and output formats, ensuring portable step definitions across language boundaries in multi-language testing projects.

513

514

The expression factory and generation system enables powerful automation and tooling capabilities while maintaining the simplicity and readability that makes Cucumber Expressions superior to regular expressions for BDD step definition matching.