or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

constants.mddata-proxy.mderror-handling.mdexpression-system.mdextension-system.mdgraph-utilities.mdindex.mdnode-execution.mdspecialized-modules.mdtype-guards.mdtype-validation.mdutilities.mdworkflow-management.md

extension-system.mddocs/

0

# Extension System

1

2

Comprehensive extension system providing data type extensions, native method access, expression parsing capabilities, and enhanced functionality for workflow expressions and data manipulation.

3

4

## Capabilities

5

6

### Expression Extensions Registry

7

8

Core extension system for registering and managing expression functions.

9

10

```typescript { .api }

11

/**

12

* Expression extensions registry and management

13

*/

14

class ExpressionExtensions {

15

/**

16

* Registry of all available extension functions

17

*/

18

static readonly functions: Record<string, Extension>;

19

20

/**

21

* Add custom extension function to registry

22

* @param name - Extension function name

23

* @param extension - Extension implementation

24

*/

25

static addExtension(name: string, extension: Extension): void;

26

27

/**

28

* Get extension function by name

29

* @param name - Extension name

30

* @returns Extension implementation or undefined

31

*/

32

static getExtension(name: string): Extension | undefined;

33

34

/**

35

* Remove extension from registry

36

* @param name - Extension name to remove

37

* @returns Boolean indicating if extension was removed

38

*/

39

static removeExtension(name: string): boolean;

40

41

/**

42

* List all available extension names

43

* @returns Array of extension names

44

*/

45

static listExtensions(): string[];

46

}

47

48

/**

49

* Extension function interface

50

*/

51

interface Extension {

52

doc: DocMetadata;

53

transform: (value: any, ...args: any[]) => any;

54

}

55

56

/**

57

* Extension documentation metadata

58

*/

59

interface DocMetadata {

60

name: string;

61

description: string;

62

returnType?: string;

63

args?: DocMetadataArgument[];

64

examples?: DocMetadataExample[];

65

section?: string;

66

hidden?: boolean;

67

}

68

69

interface DocMetadataArgument {

70

name: string;

71

type?: string;

72

description?: string;

73

default?: any;

74

optional?: boolean;

75

}

76

77

interface DocMetadataExample {

78

example: string;

79

description: string;

80

result?: any;

81

}

82

```

83

84

### Native Methods Access

85

86

Secure access to native JavaScript and Node.js methods within expressions.

87

88

```typescript { .api }

89

/**

90

* Native methods registry for expression evaluation

91

*/

92

class NativeMethods {

93

/**

94

* Get native method implementation

95

* @param methodName - Native method name

96

* @returns Native method function or undefined

97

*/

98

static getNativeMethod(methodName: string): Function | undefined;

99

100

/**

101

* Register native method for expression use

102

* @param name - Method name

103

* @param method - Method implementation

104

* @param options - Registration options

105

*/

106

static registerNativeMethod(

107

name: string,

108

method: Function,

109

options?: INativeMethodOptions

110

): void;

111

112

/**

113

* List all available native methods

114

* @returns Array of native method names

115

*/

116

static listNativeMethods(): string[];

117

}

118

119

interface INativeMethodOptions {

120

allowedInSandbox?: boolean;

121

documentation?: DocMetadata;

122

category?: string;

123

}

124

```

125

126

### Data Type Extensions

127

128

Built-in extensions for different data types with comprehensive functionality.

129

130

```typescript { .api }

131

/**

132

* Array data type extensions

133

*/

134

interface ArrayExtensions {

135

/**

136

* Split array into chunks of specified size

137

* @param size - Chunk size

138

* @returns Array of chunks

139

*/

140

chunk(size: number): any[][];

141

142

/**

143

* Remove falsy values from array

144

* @returns Array with truthy values only

145

*/

146

compact(): any[];

147

148

/**

149

* Get difference between arrays

150

* @param values - Values to exclude

151

* @returns Array with differences

152

*/

153

difference(values: any[]): any[];

154

155

/**

156

* Get first element

157

* @returns First array element

158

*/

159

first(): any;

160

161

/**

162

* Get last element

163

* @returns Last array element

164

*/

165

last(): any;

166

167

/**

168

* Remove duplicate values

169

* @returns Array with unique values

170

*/

171

unique(): any[];

172

173

/**

174

* Flatten nested arrays

175

* @param depth - Maximum depth to flatten

176

* @returns Flattened array

177

*/

178

flatten(depth?: number): any[];

179

180

/**

181

* Check if array is empty

182

* @returns Boolean indicating if array is empty

183

*/

184

isEmpty(): boolean;

185

186

/**

187

* Get array length

188

* @returns Array length

189

*/

190

length(): number;

191

192

/**

193

* Sum all numeric values

194

* @returns Sum of array values

195

*/

196

sum(): number;

197

198

/**

199

* Get average of numeric values

200

* @returns Average value

201

*/

202

average(): number;

203

204

/**

205

* Get minimum value

206

* @returns Minimum value

207

*/

208

min(): any;

209

210

/**

211

* Get maximum value

212

* @returns Maximum value

213

*/

214

max(): any;

215

}

216

217

/**

218

* String data type extensions

219

*/

220

interface StringExtensions {

221

/**

222

* Check if string contains substring

223

* @param searchString - String to search for

224

* @returns Boolean indicating if string contains substring

225

*/

226

contains(searchString: string): boolean;

227

228

/**

229

* Check if string starts with substring

230

* @param searchString - String to check

231

* @returns Boolean indicating if string starts with substring

232

*/

233

startsWith(searchString: string): boolean;

234

235

/**

236

* Check if string ends with substring

237

* @param searchString - String to check

238

* @returns Boolean indicating if string ends with substring

239

*/

240

endsWith(searchString: string): boolean;

241

242

/**

243

* Convert to title case

244

* @returns Title case string

245

*/

246

toTitleCase(): string;

247

248

/**

249

* Convert to sentence case

250

* @returns Sentence case string

251

*/

252

toSentenceCase(): string;

253

254

/**

255

* Remove HTML tags

256

* @returns String without HTML tags

257

*/

258

stripTags(): string;

259

260

/**

261

* URL encode string

262

* @returns URL encoded string

263

*/

264

urlEncode(): string;

265

266

/**

267

* URL decode string

268

* @returns URL decoded string

269

*/

270

urlDecode(): string;

271

272

/**

273

* Generate hash of string

274

* @param algorithm - Hash algorithm (default: 'md5')

275

* @returns Hash string

276

*/

277

hash(algorithm?: string): string;

278

279

/**

280

* Extract email addresses from string

281

* @returns Array of email addresses

282

*/

283

extractEmails(): string[];

284

285

/**

286

* Extract URLs from string

287

* @returns Array of URLs

288

*/

289

extractUrls(): string[];

290

291

/**

292

* Truncate string to specified length

293

* @param length - Maximum length

294

* @param suffix - Suffix to add (default: '...')

295

* @returns Truncated string

296

*/

297

truncate(length: number, suffix?: string): string;

298

}

299

300

/**

301

* Number data type extensions

302

*/

303

interface NumberExtensions {

304

/**

305

* Get absolute value

306

* @returns Absolute value

307

*/

308

abs(): number;

309

310

/**

311

* Round up to nearest integer

312

* @returns Ceiling value

313

*/

314

ceil(): number;

315

316

/**

317

* Round down to nearest integer

318

* @returns Floor value

319

*/

320

floor(): number;

321

322

/**

323

* Round to specified precision

324

* @param precision - Number of decimal places

325

* @returns Rounded number

326

*/

327

round(precision?: number): number;

328

329

/**

330

* Check if value is NaN

331

* @returns Boolean indicating if value is NaN

332

*/

333

isNaN(): boolean;

334

335

/**

336

* Check if value is finite

337

* @returns Boolean indicating if value is finite

338

*/

339

isFinite(): boolean;

340

341

/**

342

* Format number with locale options

343

* @param options - Formatting options

344

* @returns Formatted number string

345

*/

346

format(options?: NumberFormatOptions): string;

347

348

/**

349

* Convert to percentage

350

* @param decimals - Number of decimal places

351

* @returns Percentage string

352

*/

353

toPercent(decimals?: number): string;

354

355

/**

356

* Convert to currency format

357

* @param currency - Currency code

358

* @param locale - Locale code

359

* @returns Currency formatted string

360

*/

361

toCurrency(currency?: string, locale?: string): string;

362

}

363

364

interface NumberFormatOptions {

365

locale?: string;

366

style?: 'decimal' | 'currency' | 'percent';

367

currency?: string;

368

minimumFractionDigits?: number;

369

maximumFractionDigits?: number;

370

}

371

```

372

373

### Date Extensions

374

375

Comprehensive date and time manipulation extensions.

376

377

```typescript { .api }

378

/**

379

* Date data type extensions

380

*/

381

interface DateExtensions {

382

/**

383

* Format date using specified format string

384

* @param format - Format string (e.g., 'yyyy-MM-dd')

385

* @returns Formatted date string

386

*/

387

format(format: string): string;

388

389

/**

390

* Convert to ISO string

391

* @returns ISO formatted date string

392

*/

393

toISOString(): string;

394

395

/**

396

* Get beginning of time unit

397

* @param unit - Time unit ('day', 'month', 'year', etc.)

398

* @returns Date at beginning of unit

399

*/

400

beginningOf(unit: DateUnit): Date;

401

402

/**

403

* Get end of time unit

404

* @param unit - Time unit

405

* @returns Date at end of unit

406

*/

407

endOf(unit: DateUnit): Date;

408

409

/**

410

* Add duration to date

411

* @param duration - Duration object or number

412

* @param unit - Time unit (if duration is number)

413

* @returns New date with added duration

414

*/

415

plus(duration: Duration | number, unit?: DateUnit): Date;

416

417

/**

418

* Subtract duration from date

419

* @param duration - Duration object or number

420

* @param unit - Time unit (if duration is number)

421

* @returns New date with subtracted duration

422

*/

423

minus(duration: Duration | number, unit?: DateUnit): Date;

424

425

/**

426

* Get difference between dates

427

* @param date - Date to compare with

428

* @param unit - Unit for difference calculation

429

* @returns Difference in specified unit

430

*/

431

diff(date: Date, unit?: DateUnit): number;

432

433

/**

434

* Check if date is before another date

435

* @param date - Date to compare with

436

* @returns Boolean indicating if date is before

437

*/

438

isBefore(date: Date): boolean;

439

440

/**

441

* Check if date is after another date

442

* @param date - Date to compare with

443

* @returns Boolean indicating if date is after

444

*/

445

isAfter(date: Date): boolean;

446

447

/**

448

* Check if date is between two dates

449

* @param start - Start date

450

* @param end - End date

451

* @returns Boolean indicating if date is between

452

*/

453

isBetween(start: Date, end: Date): boolean;

454

}

455

456

type DateUnit = 'millisecond' | 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';

457

458

interface Duration {

459

years?: number;

460

months?: number;

461

weeks?: number;

462

days?: number;

463

hours?: number;

464

minutes?: number;

465

seconds?: number;

466

milliseconds?: number;

467

}

468

```

469

470

### Object Extensions

471

472

Object manipulation and transformation extensions.

473

474

```typescript { .api }

475

/**

476

* Object data type extensions

477

*/

478

interface ObjectExtensions {

479

/**

480

* Get object keys

481

* @returns Array of object keys

482

*/

483

keys(): string[];

484

485

/**

486

* Get object values

487

* @returns Array of object values

488

*/

489

values(): any[];

490

491

/**

492

* Get object entries as key-value pairs

493

* @returns Array of [key, value] pairs

494

*/

495

entries(): Array<[string, any]>;

496

497

/**

498

* Check if object has property

499

* @param key - Property key to check

500

* @returns Boolean indicating if property exists

501

*/

502

hasKey(key: string): boolean;

503

504

/**

505

* Pick specified properties

506

* @param keys - Keys to pick

507

* @returns Object with only specified keys

508

*/

509

pick(keys: string[]): object;

510

511

/**

512

* Omit specified properties

513

* @param keys - Keys to omit

514

* @returns Object without specified keys

515

*/

516

omit(keys: string[]): object;

517

518

/**

519

* Merge with another object

520

* @param other - Object to merge with

521

* @returns Merged object

522

*/

523

merge(other: object): object;

524

525

/**

526

* Convert keys to camelCase

527

* @returns Object with camelCase keys

528

*/

529

camelCaseKeys(): object;

530

531

/**

532

* Convert keys to snake_case

533

* @returns Object with snake_case keys

534

*/

535

snakeCaseKeys(): object;

536

537

/**

538

* Flatten nested object

539

* @param separator - Key separator (default: '.')

540

* @returns Flattened object

541

*/

542

flatten(separator?: string): object;

543

544

/**

545

* Unflatten dot notation object

546

* @returns Nested object structure

547

*/

548

unflatten(): object;

549

}

550

```

551

552

### Expression Parser

553

554

Advanced expression parsing and validation capabilities.

555

556

```typescript { .api }

557

/**

558

* Expression parser module

559

*/

560

namespace ExpressionParser {

561

/**

562

* Parse expression string into AST

563

* @param expression - Expression string to parse

564

* @returns Parsed expression AST

565

*/

566

function parse(expression: string): ExpressionAST;

567

568

/**

569

* Validate expression syntax

570

* @param expression - Expression to validate

571

* @returns Validation result

572

*/

573

function validate(expression: string): ExpressionValidationResult;

574

575

/**

576

* Extract all variables from expression

577

* @param expression - Expression string

578

* @returns Array of variable names

579

*/

580

function extractVariables(expression: string): string[];

581

582

/**

583

* Get expression dependencies

584

* @param expression - Expression string

585

* @returns Dependency information

586

*/

587

function getDependencies(expression: string): ExpressionDependencies;

588

589

/**

590

* Transform expression AST

591

* @param ast - Expression AST

592

* @param transformer - Transformation function

593

* @returns Transformed AST

594

*/

595

function transform(

596

ast: ExpressionAST,

597

transformer: (node: ASTNode) => ASTNode

598

): ExpressionAST;

599

}

600

601

interface ExpressionAST {

602

type: string;

603

body: ASTNode[];

604

sourceType: 'script' | 'module';

605

}

606

607

interface ASTNode {

608

type: string;

609

[key: string]: any;

610

}

611

612

interface ExpressionValidationResult {

613

isValid: boolean;

614

errors: ExpressionSyntaxError[];

615

warnings: ExpressionWarning[];

616

}

617

618

interface ExpressionDependencies {

619

variables: string[];

620

functions: string[];

621

dataRefs: string[];

622

nodeRefs: string[];

623

}

624

```

625

626

**Usage Examples:**

627

628

```typescript

629

import {

630

ExpressionExtensions,

631

NativeMethods,

632

ExpressionParser

633

} from "n8n-workflow";

634

635

// Register custom extension

636

ExpressionExtensions.addExtension('customTransform', {

637

doc: {

638

name: 'customTransform',

639

description: 'Transform data using custom logic',

640

returnType: 'any',

641

args: [

642

{ name: 'data', type: 'any', description: 'Data to transform' },

643

{ name: 'options', type: 'object', optional: true, description: 'Transform options' }

644

],

645

examples: [

646

{

647

example: 'data.customTransform({ format: "uppercase" })',

648

description: 'Transform data to uppercase format'

649

}

650

]

651

},

652

transform: (value: any, options: any = {}) => {

653

if (options.format === 'uppercase' && typeof value === 'string') {

654

return value.toUpperCase();

655

}

656

return value;

657

}

658

});

659

660

// Use data type extensions in expressions

661

const arrayExpression = `

662

{{

663

$json.items

664

.chunk(3)

665

.map(chunk => chunk.sum())

666

.unique()

667

.sort()

668

}}

669

`;

670

671

const stringExpression = `

672

{{

673

$json.description

674

.stripTags()

675

.truncate(100)

676

.toTitleCase()

677

}}

678

`;

679

680

const dateExpression = `

681

{{

682

$json.createdAt

683

.beginningOf('day')

684

.plus(1, 'week')

685

.format('yyyy-MM-dd')

686

}}

687

`;

688

689

// Register native method

690

NativeMethods.registerNativeMethod('customMath', Math.pow, {

691

allowedInSandbox: true,

692

documentation: {

693

name: 'customMath',

694

description: 'Calculate power of a number',

695

args: [

696

{ name: 'base', type: 'number', description: 'Base number' },

697

{ name: 'exponent', type: 'number', description: 'Exponent' }

698

]

699

},

700

category: 'math'

701

});

702

703

// Parse and analyze expressions

704

const expressionCode = '{{ $json.user.name.toTitleCase() + " - " + $json.createdAt.format("yyyy-MM-dd") }}';

705

706

const ast = ExpressionParser.parse(expressionCode);

707

console.log('Parsed AST:', ast);

708

709

const validation = ExpressionParser.validate(expressionCode);

710

if (!validation.isValid) {

711

console.log('Expression validation errors:', validation.errors);

712

}

713

714

const variables = ExpressionParser.extractVariables(expressionCode);

715

console.log('Variables used:', variables); // ['$json']

716

717

const dependencies = ExpressionParser.getDependencies(expressionCode);

718

console.log('Expression dependencies:', dependencies);

719

720

// List available extensions

721

const availableExtensions = ExpressionExtensions.listExtensions();

722

console.log('Available extensions:', availableExtensions);

723

724

// Get extension documentation

725

const stringExtension = ExpressionExtensions.getExtension('toTitleCase');

726

if (stringExtension) {

727

console.log('Extension documentation:', stringExtension.doc);

728

}

729

730

// Complex data manipulation using extensions

731

const complexExpression = `

732

{{

733

$json.users

734

.filter(user => user.active && user.email.contains('@company.com'))

735

.map(user => ({

736

id: user.id,

737

name: user.name.toTitleCase(),

738

email: user.email.toLowerCase(),

739

joinDate: user.joinDate.format('MMM dd, yyyy'),

740

tenure: user.joinDate.diff($now, 'months')

741

}))

742

.sort((a, b) => a.tenure - b.tenure)

743

.chunk(10)

744

.first()

745

}}

746

`;

747

748

// Object transformation example

749

const objectTransformExpression = `

750

{{

751

$json.apiResponse

752

.pick(['id', 'name', 'email', 'metadata'])

753

.camelCaseKeys()

754

.merge({

755

processedAt: $now.toISOString(),

756

status: 'processed'

757

})

758

}}

759

`;

760

761

console.log('Complex expressions ready for evaluation');

762

```