or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdcompilation.mdcontext.mdfilters.mdhelpers.mdindex.mdparsing.mdrendering.md

filters.mddocs/

0

# Filter System

1

2

Built-in and extensible filtering system for data transformation with automatic escaping support and custom filter registration.

3

4

## Capabilities

5

6

### Built-in Filters

7

8

Dust provides several built-in filters for common data transformations and security escaping.

9

10

```javascript { .api }

11

/**

12

* Built-in filter functions

13

*/

14

const filters: {

15

/** HTML escape filter - escapes HTML entities for safe output */

16

h: (value: any) => string;

17

/** JavaScript string escape filter - escapes for safe JS string literals */

18

j: (value: any) => string;

19

/** URL encode filter - encodes using encodeURI */

20

u: (value: any) => string;

21

/** URL component encode filter - encodes using encodeURIComponent */

22

uc: (value: any) => string;

23

/** JSON stringify filter - safe JSON conversion for JavaScript */

24

js: (value: any) => string;

25

/** JSON parse filter - parses JSON strings to objects */

26

jp: (value: any) => any;

27

};

28

```

29

30

**Usage Examples:**

31

32

```javascript

33

const dust = require('dustjs-linkedin');

34

35

// Template usage with built-in filters:

36

// {name|h} - HTML escape

37

// {script|j} - JavaScript string escape

38

// {url|u} - URL encode

39

// {param|uc} - URL component encode

40

// {data|js} - JSON stringify

41

// {jsonString|jp} - JSON parse

42

43

// Test built-in filters directly

44

console.log(dust.filters.h('<script>alert("xss")</script>'));

45

// Output: "&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;"

46

47

console.log(dust.filters.j('Hello "world"\nNew line'));

48

// Output: "Hello \\\"world\\\"\\nNew line"

49

50

console.log(dust.filters.u('hello world'));

51

// Output: "hello%20world"

52

53

console.log(dust.filters.uc('hello@world.com'));

54

// Output: "hello%40world.com"

55

56

console.log(dust.filters.js({name: 'test', value: 123}));

57

// Output: '{"name":"test","value":123}'

58

59

console.log(dust.filters.jp('{"name":"test","value":123}'));

60

// Output: {name: 'test', value: 123}

61

```

62

63

### Filter Application

64

65

Core function for applying filters to values with automatic escaping.

66

67

```javascript { .api }

68

/**

69

* Applies filter chain to string value

70

* @param string - Input value to filter

71

* @param auto - Automatic filter (usually 'h' for HTML escape)

72

* @param filters - Array of filter names to apply in sequence

73

* @param context - Template context for filter execution

74

* @returns Filtered string value

75

*/

76

function filter(

77

string: any,

78

auto: string | null,

79

filters: string[],

80

context: Context

81

): string;

82

```

83

84

**Usage Examples:**

85

86

```javascript

87

const context = dust.context({});

88

89

// Apply single filter

90

const htmlEscaped = dust.filter('<script>alert("xss")</script>', null, ['h'], context);

91

console.log(htmlEscaped); // "&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;"

92

93

// Apply multiple filters in sequence

94

const multiFiltered = dust.filter('Hello World', null, ['j', 'u'], context);

95

// First applies 'j' (JavaScript escape), then 'u' (URL encode)

96

97

// Apply with automatic filter

98

const autoFiltered = dust.filter('<div>Content</div>', 'h', [], context);

99

console.log(autoFiltered); // "&lt;div&gt;Content&lt;/div&gt;" (auto HTML escaped)

100

101

// Chain filters

102

const chained = dust.filter({name: 'test'}, null, ['js', 'u'], context);

103

// First converts to JSON, then URL encodes the result

104

```

105

106

### Escape Functions

107

108

Individual escape functions used by filters and available for direct use.

109

110

```javascript { .api }

111

/**

112

* HTML entity escape function

113

* @param string - String to escape

114

* @returns String with HTML entities escaped

115

*/

116

function escapeHtml(string: any): string;

117

118

/**

119

* JavaScript string escape function

120

* @param string - String to escape for JS

121

* @returns String safe for JavaScript string literals

122

*/

123

function escapeJs(string: any): string;

124

125

/**

126

* Safe JSON stringify function

127

* @param obj - Object to stringify

128

* @returns JSON string safe for JavaScript execution

129

*/

130

function escapeJSON(obj: any): string;

131

```

132

133

**Usage Examples:**

134

135

```javascript

136

// Direct use of escape functions

137

const htmlSafe = dust.escapeHtml('<script>alert("xss")</script>');

138

console.log(htmlSafe); // "&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;"

139

140

const jsSafe = dust.escapeJs('Line 1\nLine 2\t"Quote"');

141

console.log(jsSafe); // "Line 1\\nLine 2\\t\\\"Quote\\\""

142

143

const jsonSafe = dust.escapeJSON({

144

name: 'Test',

145

code: '<script>alert("xss")</script>',

146

special: '\u2028\u2029' // Line/paragraph separators

147

});

148

console.log(jsonSafe); // Safely escaped JSON string

149

150

// Use in custom helpers

151

dust.helpers.safeOutput = (chunk, context, bodies, params) => {

152

const rawData = params.data;

153

const escaped = dust.escapeHtml(rawData);

154

return chunk.write(escaped);

155

};

156

```

157

158

## Custom Filters

159

160

### Filter Registration

161

162

How to register custom filters for template use.

163

164

```javascript { .api }

165

/**

166

* Register custom filter by adding to filters object

167

*/

168

dust.filters.customFilter = (value: any) => string;

169

```

170

171

**Usage Examples:**

172

173

```javascript

174

// Register a simple text transformation filter

175

dust.filters.capitalize = (value) => {

176

if (typeof value !== 'string') return value;

177

return value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();

178

};

179

180

// Register a number formatting filter

181

dust.filters.currency = (value) => {

182

const number = parseFloat(value);

183

if (isNaN(number)) return value;

184

return '$' + number.toFixed(2);

185

};

186

187

// Register a date formatting filter

188

dust.filters.dateFormat = (value) => {

189

const date = new Date(value);

190

if (isNaN(date.getTime())) return value;

191

return date.toLocaleDateString('en-US');

192

};

193

194

// Register a text truncation filter

195

dust.filters.truncate = (value) => {

196

if (typeof value !== 'string') return value;

197

return value.length > 50 ? value.substring(0, 50) + '...' : value;

198

};

199

200

// Template usage:

201

// {name|capitalize}

202

// {price|currency}

203

// {date|dateFormat}

204

// {description|truncate}

205

```

206

207

### Advanced Custom Filters

208

209

More complex filter implementations with error handling and configuration.

210

211

```javascript

212

// Filter with configuration

213

dust.filters.truncateBy = (value, length = 50) => {

214

if (typeof value !== 'string') return value;

215

const maxLength = parseInt(length) || 50;

216

return value.length > maxLength ? value.substring(0, maxLength) + '...' : value;

217

};

218

219

// Filter with multiple transformations

220

dust.filters.slug = (value) => {

221

if (typeof value !== 'string') return value;

222

return value

223

.toLowerCase()

224

.replace(/[^\w\s-]/g, '') // Remove special characters

225

.replace(/\s+/g, '-') // Replace spaces with hyphens

226

.replace(/-+/g, '-') // Collapse multiple hyphens

227

.trim('-'); // Remove leading/trailing hyphens

228

};

229

230

// Filter with error handling

231

dust.filters.safeNumber = (value) => {

232

try {

233

const number = parseFloat(value);

234

return isNaN(number) ? '0' : number.toString();

235

} catch (err) {

236

dust.log('Filter error in safeNumber: ' + err.message, 'ERROR');

237

return '0';

238

}

239

};

240

241

// Filter that uses context (advanced - requires custom implementation)

242

dust.filters.translate = function(value, context) {

243

const translations = context.get('translations') || {};

244

return translations[value] || value;

245

};

246

```

247

248

### Filter Chaining

249

250

Understanding how multiple filters work together in sequence.

251

252

```javascript

253

// Filters are applied left to right

254

// Template: {name|capitalize|truncate}

255

// 1. First applies capitalize filter

256

// 2. Then applies truncate filter to the result

257

258

// Example filter chain execution:

259

const input = 'hello world this is a long string';

260

261

// Step 1: Apply capitalize

262

const step1 = dust.filters.capitalize(input); // "Hello world this is a long string"

263

264

// Step 2: Apply truncate

265

const final = dust.filters.truncate(step1); // "Hello world this is a long string..."

266

267

// Register filters that work well together

268

dust.filters.clean = (value) => {

269

if (typeof value !== 'string') return value;

270

return value.trim().replace(/\s+/g, ' '); // Clean whitespace

271

};

272

273

dust.filters.title = (value) => {

274

if (typeof value !== 'string') return value;

275

return value.replace(/\w\S*/g, (txt) =>

276

txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()

277

);

278

};

279

280

// Template usage for chaining:

281

// {text|clean|title} - First clean whitespace, then title case

282

```

283

284

## Automatic Escaping

285

286

### Default Auto-Escape Behavior

287

288

Dust automatically applies HTML escaping by default for security.

289

290

```javascript

291

// By default, all variable references are HTML escaped

292

// Template: {userInput}

293

// If userInput = '<script>alert("xss")</script>'

294

// Output: &lt;script&gt;alert("xss")&lt;/script&gt;

295

296

// Disable auto-escaping with 's' filter (suppress)

297

// Template: {userInput|s}

298

// Output: <script>alert("xss")</script> (DANGEROUS!)

299

300

// Override auto-escape with specific filter

301

// Template: {userInput|j} - JavaScript escape instead of HTML

302

```

303

304

### Configuring Auto-Escape

305

306

Control automatic escaping behavior in templates.

307

308

```javascript

309

// The default auto-escape filter is 'h' (HTML escape)

310

// This is applied automatically to all references unless:

311

// 1. Explicitly suppressed with |s

312

// 2. Overridden with another filter

313

314

// Example configurations in templates:

315

// {value} - Auto HTML escaped

316

// {value|s} - No escaping (suppress)

317

// {value|j} - JavaScript escaped (overrides auto HTML)

318

// {value|h|j} - HTML escaped, then JavaScript escaped

319

// {value|s|h} - Suppress auto, then explicitly HTML escape

320

```

321

322

### Security Considerations

323

324

Best practices for safe filter usage.

325

326

```javascript

327

// SAFE: Always escape user content for HTML output

328

// Template: <div>{userContent}</div>

329

// Automatically HTML escaped by default

330

331

// DANGEROUS: Suppressing escaping

332

// Template: <div>{userContent|s}</div>

333

// Only use |s for trusted content!

334

335

// SAFE: Appropriate escaping for context

336

// Template: <script>var data = "{jsonData|js}";</script>

337

// Uses JavaScript escaping for script context

338

339

// SAFE: URL context escaping

340

// Template: <a href="?q={query|uc}">Link</a>

341

// Uses URL component encoding for query parameters

342

343

// Register security-focused filters

344

dust.filters.stripTags = (value) => {

345

if (typeof value !== 'string') return value;

346

return value.replace(/<[^>]*>/g, ''); // Remove HTML tags

347

};

348

349

dust.filters.allowedTags = (value) => {

350

if (typeof value !== 'string') return value;

351

// Allow only specific safe tags

352

return value.replace(/<(?!\/?(?:b|i|em|strong|p|br)\b)[^>]*>/gi, '');

353

};

354

```

355

356

## Filter Performance and Best Practices

357

358

### Performance Optimization

359

360

Best practices for efficient filter usage.

361

362

```javascript

363

// EFFICIENT: Simple, focused filters

364

dust.filters.upper = (value) => {

365

return typeof value === 'string' ? value.toUpperCase() : value;

366

};

367

368

// LESS EFFICIENT: Complex processing in filters

369

dust.filters.complexProcess = (value) => {

370

// Avoid heavy computations in filters

371

// Consider doing this in helpers or before rendering

372

return expensiveTransformation(value);

373

};

374

375

// GOOD: Cache expensive computations

376

const computationCache = new Map();

377

dust.filters.cachedTransform = (value) => {

378

if (computationCache.has(value)) {

379

return computationCache.get(value);

380

}

381

382

const result = expensiveComputation(value);

383

computationCache.set(value, result);

384

return result;

385

};

386

```

387

388

### Error Handling in Filters

389

390

Robust error handling patterns for custom filters.

391

392

```javascript

393

// Robust filter with error handling

394

dust.filters.robustFilter = (value) => {

395

try {

396

// Type checking

397

if (value === null || value === undefined) {

398

return '';

399

}

400

401

// Safe conversion

402

const stringValue = String(value);

403

404

// Process with error handling

405

return processValue(stringValue);

406

407

} catch (err) {

408

// Log error for debugging

409

dust.log(`Filter error: ${err.message}`, 'ERROR');

410

411

// Return safe fallback

412

return String(value || '');

413

}

414

};

415

416

// Filter with validation

417

dust.filters.emailMask = (value) => {

418

if (typeof value !== 'string') return value;

419

420

// Validate email format

421

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

422

if (!emailRegex.test(value)) {

423

return '[Invalid Email]';

424

}

425

426

// Mask email

427

const [local, domain] = value.split('@');

428

const maskedLocal = local.charAt(0) + '*'.repeat(local.length - 2) + local.charAt(local.length - 1);

429

return `${maskedLocal}@${domain}`;

430

};

431

```

432

433

### Filter Testing

434

435

Patterns for testing custom filters.

436

437

```javascript

438

// Test custom filters

439

function testFilters() {

440

const testCases = [

441

{ input: 'hello world', expected: 'Hello World', filter: 'title' },

442

{ input: 123.456, expected: '$123.46', filter: 'currency' },

443

{ input: '<script>alert()</script>', expected: '[sanitized]', filter: 'sanitize' }

444

];

445

446

testCases.forEach(testCase => {

447

const result = dust.filters[testCase.filter](testCase.input);

448

console.log(`Filter ${testCase.filter}: ${result === testCase.expected ? 'PASS' : 'FAIL'}`);

449

});

450

}

451

452

// Unit test helper for filters

453

function testFilter(filterName, testCases) {

454

const filter = dust.filters[filterName];

455

if (!filter) {

456

console.error(`Filter ${filterName} not found`);

457

return;

458

}

459

460

testCases.forEach((testCase, index) => {

461

const result = filter(testCase.input);

462

const passed = result === testCase.expected;

463

console.log(`Test ${index + 1}: ${passed ? 'PASS' : 'FAIL'}`);

464

if (!passed) {

465

console.log(` Expected: ${testCase.expected}`);

466

console.log(` Actual: ${result}`);

467

}

468

});

469

}

470

```