0
# Context System
1
2
Stack-based context system for data resolution with scoping, inheritance, and block management in Dust templates.
3
4
## Capabilities
5
6
### Context Creation
7
8
Functions for creating and managing template contexts that provide data resolution during rendering.
9
10
```javascript { .api }
11
/**
12
* Creates base template context
13
* @param global - Global data object accessible throughout template
14
* @param options - Context configuration options
15
* @returns Context instance for template rendering
16
*/
17
function context(global: any, options?: ContextOptions): Context;
18
19
/**
20
* Alias for context() function
21
* @param global - Global data object
22
* @param options - Context configuration options
23
* @returns Context instance
24
*/
25
function makeBase(global: any, options?: ContextOptions): Context;
26
27
interface ContextOptions {
28
/** Template name for debugging */
29
templateName?: string;
30
/** Block definitions for template inheritance */
31
blocks?: { [blockName: string]: any };
32
/** Additional context configuration */
33
[key: string]: any;
34
}
35
```
36
37
**Usage Examples:**
38
39
```javascript
40
const dust = require('dustjs-linkedin');
41
42
// Basic context creation
43
const ctx = dust.context({
44
user: { name: 'Alice', role: 'admin' },
45
site: { title: 'My App', version: '1.0' }
46
});
47
48
// Context with options
49
const ctxWithOptions = dust.context({
50
users: [{ name: 'Bob' }, { name: 'Carol' }]
51
}, {
52
templateName: 'user-list',
53
blocks: { header: 'Custom Header' }
54
});
55
56
// Using makeBase alias
57
const baseCtx = dust.makeBase({
58
config: { debug: true },
59
helpers: { customHelper: () => 'Custom' }
60
});
61
```
62
63
### Context Type Checking
64
65
Utility function to determine if an object is a Dust context.
66
67
```javascript { .api }
68
/**
69
* Tests if object is a Dust context
70
* @param obj - Object to test
71
* @returns true if object is a Context instance
72
*/
73
function isContext(obj: any): boolean;
74
75
/**
76
* Static method to wrap context data
77
* @param context - Context data or existing Context instance
78
* @param name - Template name for debugging
79
* @returns Context instance
80
*/
81
Context.wrap(context: any, name?: string): Context;
82
```
83
84
**Usage Examples:**
85
86
```javascript
87
const ctx = dust.context({ data: 'value' });
88
const plainObject = { data: 'value' };
89
90
console.log(dust.isContext(ctx)); // true
91
console.log(dust.isContext(plainObject)); // false
92
93
// Useful in helper functions
94
function myHelper(chunk, context, bodies, params) {
95
if (!dust.isContext(context)) {
96
throw new Error('Invalid context provided to helper');
97
}
98
// Helper implementation...
99
}
100
```
101
102
## Context Instance Methods
103
104
### Data Access and Resolution
105
106
Methods for accessing and resolving data within the context stack.
107
108
```javascript { .api }
109
interface Context {
110
/**
111
* Get value from context by path
112
* @param path - Dot-separated path or array of keys
113
* @param cur - Current context data (optional)
114
* @returns Resolved value or undefined
115
*/
116
get(path: string | string[], cur?: any): any;
117
118
/**
119
* Get current context data at top of stack
120
* @returns Current data object
121
*/
122
current(): any;
123
124
/**
125
* Get template name for debugging
126
* @returns Template name string or undefined
127
*/
128
getTemplateName(): string | undefined;
129
}
130
```
131
132
**Usage Examples:**
133
134
```javascript
135
const ctx = dust.context({
136
user: {
137
profile: { name: 'Alice', email: 'alice@example.com' },
138
settings: { theme: 'dark', notifications: true }
139
},
140
items: ['apple', 'banana', 'cherry']
141
});
142
143
// Simple path resolution
144
console.log(ctx.get('user.profile.name')); // 'Alice'
145
console.log(ctx.get('user.settings.theme')); // 'dark'
146
147
// Array path resolution
148
console.log(ctx.get(['user', 'profile', 'email'])); // 'alice@example.com'
149
150
// Array index access
151
console.log(ctx.get('items.0')); // 'apple'
152
console.log(ctx.get('items.2')); // 'cherry'
153
154
// Non-existent path
155
console.log(ctx.get('user.invalid.path')); // undefined
156
157
// Current context data
158
console.log(ctx.current()); // Full context object
159
```
160
161
### Context Stack Management
162
163
Methods for manipulating the context stack during template execution.
164
165
```javascript { .api }
166
interface Context {
167
/**
168
* Push new data onto context stack
169
* @param head - New context data to push
170
* @param idx - Index for array iterations (optional)
171
* @param len - Length for array iterations (optional)
172
* @returns New context with pushed data
173
*/
174
push(head: any, idx?: number, len?: number): Context;
175
176
/**
177
* Remove top item from context stack
178
* @returns Context with popped data
179
*/
180
pop(): Context;
181
182
/**
183
* Create new context with different base data
184
* @param head - New base data
185
* @returns New context instance
186
*/
187
rebase(head: any): Context;
188
189
/**
190
* Clone current context
191
* @returns New context instance with same data
192
*/
193
clone(): Context;
194
}
195
```
196
197
**Usage Examples:**
198
199
```javascript
200
const baseCtx = dust.context({
201
global: 'value',
202
config: { debug: true }
203
});
204
205
// Push new context data
206
const userCtx = baseCtx.push({
207
name: 'Bob',
208
role: 'editor'
209
});
210
211
console.log(userCtx.get('name')); // 'Bob' (from pushed data)
212
console.log(userCtx.get('global')); // 'value' (from base context)
213
214
// Push with array iteration info
215
const items = ['a', 'b', 'c'];
216
items.forEach((item, idx) => {
217
const itemCtx = baseCtx.push(item, idx, items.length);
218
console.log(itemCtx.get('@index')); // Current index
219
console.log(itemCtx.get('@length')); // Array length
220
});
221
222
// Pop context
223
const poppedCtx = userCtx.pop();
224
console.log(poppedCtx.get('name')); // undefined (popped)
225
console.log(poppedCtx.get('global')); // 'value' (still available)
226
227
// Rebase context
228
const rebasedCtx = baseCtx.rebase({
229
newBase: 'data',
230
different: 'values'
231
});
232
233
// Clone context
234
const clonedCtx = baseCtx.clone();
235
console.log(clonedCtx.get('global')); // 'value'
236
```
237
238
### Block Management
239
240
Methods for managing template blocks used in template inheritance.
241
242
```javascript { .api }
243
interface Context {
244
/**
245
* Get block by name
246
* @param key - Block name
247
* @returns Block definition or undefined
248
*/
249
getBlock(key: string): any;
250
251
/**
252
* Add local blocks to context
253
* @param locals - Object containing block definitions
254
* @returns New context with added blocks
255
*/
256
shiftBlocks(locals: { [blockName: string]: any }): Context;
257
}
258
```
259
260
**Usage Examples:**
261
262
```javascript
263
// Context with blocks
264
const ctx = dust.context({ data: 'value' }, {
265
blocks: {
266
header: 'Custom Header Block',
267
footer: 'Custom Footer Block'
268
}
269
});
270
271
// Get block by name
272
console.log(ctx.getBlock('header')); // 'Custom Header Block'
273
console.log(ctx.getBlock('sidebar')); // undefined
274
275
// Add local blocks
276
const extendedCtx = ctx.shiftBlocks({
277
sidebar: 'Sidebar Block',
278
navigation: 'Nav Block'
279
});
280
281
console.log(extendedCtx.getBlock('sidebar')); // 'Sidebar Block'
282
console.log(extendedCtx.getBlock('header')); // 'Custom Header Block' (inherited)
283
```
284
285
### Template Body Resolution
286
287
Method for resolving template bodies to string output.
288
289
```javascript { .api }
290
interface Context {
291
/**
292
* Resolve template body to string output
293
* @param body - Template body function or content
294
* @returns Promise resolving to rendered string
295
*/
296
resolve(body: any): Promise<string>;
297
}
298
```
299
300
**Usage Examples:**
301
302
```javascript
303
// Used internally by Dust during template rendering
304
// Typically not called directly by user code
305
const ctx = dust.context({ name: 'Alice' });
306
307
// In a helper function
308
function customHelper(chunk, context, bodies, params) {
309
if (bodies.block) {
310
return context.resolve(bodies.block).then(content => {
311
return chunk.write(`<div class="wrapper">${content}</div>`);
312
});
313
}
314
return chunk;
315
}
316
```
317
318
## Context Data Resolution
319
320
### Path Resolution Rules
321
322
Understanding how Dust resolves data paths within the context stack:
323
324
```javascript
325
const ctx = dust.context({
326
// Global data
327
global: 'global-value',
328
user: { name: 'Alice' }
329
}).push({
330
// Local data (top of stack)
331
local: 'local-value',
332
user: { role: 'admin' } // Shadows global user
333
});
334
335
// Resolution priority (top of stack first)
336
console.log(ctx.get('local')); // 'local-value' (local only)
337
console.log(ctx.get('global')); // 'global-value' (global only)
338
console.log(ctx.get('user.name')); // undefined (local user has no name)
339
console.log(ctx.get('user.role')); // 'admin' (local user.role)
340
341
// Explicit current context access
342
console.log(ctx.current().local); // 'local-value'
343
```
344
345
### Special Context Variables
346
347
Dust provides special variables during iterations and template execution:
348
349
```javascript
350
// Array iteration provides special variables
351
const items = ['apple', 'banana', 'cherry'];
352
const ctx = dust.context({ items });
353
354
// When iterating over array (internally handled by sections)
355
items.forEach((item, idx) => {
356
const iterCtx = ctx.push(item, idx, items.length);
357
358
console.log(iterCtx.get('@index')); // Current index (0, 1, 2)
359
console.log(iterCtx.get('@length')); // Array length (3)
360
console.log(iterCtx.get('@first')); // true for first item
361
console.log(iterCtx.get('@last')); // true for last item
362
console.log(iterCtx.get('@odd')); // true for odd indices
363
console.log(iterCtx.get('@even')); // true for even indices
364
});
365
366
// Object iteration provides key access
367
const obj = { a: 1, b: 2, c: 3 };
368
Object.keys(obj).forEach((key, idx) => {
369
const iterCtx = ctx.push(obj[key], idx, Object.keys(obj).length);
370
iterCtx.key = key; // Key is available as property
371
372
console.log(iterCtx.get('@key')); // Current key ('a', 'b', 'c')
373
console.log(iterCtx.get('.')); // Current value (1, 2, 3)
374
});
375
```
376
377
## Advanced Context Usage
378
379
### Context in Helper Functions
380
381
How context is used within helper functions:
382
383
```javascript
384
// Register a helper that uses context
385
dust.helpers.debugContext = (chunk, context, bodies, params) => {
386
// Access current data
387
const currentData = context.current();
388
389
// Get specific values
390
const userName = context.get('user.name');
391
const templateName = context.getTemplateName();
392
393
// Push new context for body execution
394
const newContext = context.push({
395
debug: true,
396
timestamp: Date.now()
397
});
398
399
// Render body with new context
400
return chunk.render(bodies.block, newContext);
401
};
402
403
// Usage in template: {@debugContext}Content with debug info{/debugContext}
404
```
405
406
### Context Performance Considerations
407
408
Best practices for efficient context usage:
409
410
```javascript
411
// Efficient: Reuse base contexts
412
const baseCtx = dust.context({
413
config: appConfig,
414
helpers: customHelpers
415
});
416
417
// For each render, push specific data
418
function renderUserTemplate(userData) {
419
const userCtx = baseCtx.push(userData);
420
return dust.render('user-template', userCtx, callback);
421
}
422
423
// Avoid: Creating new base contexts repeatedly
424
function inefficientRender(userData) {
425
const ctx = dust.context({
426
config: appConfig, // Recreated each time
427
...userData
428
});
429
return dust.render('user-template', ctx, callback);
430
}
431
```
432
433
### Context Debugging
434
435
Utilities for debugging context resolution:
436
437
```javascript
438
// Debug helper to inspect context
439
dust.helpers.inspectContext = (chunk, context) => {
440
const debug = {
441
current: context.current(),
442
templateName: context.getTemplateName(),
443
stackDepth: 'not directly accessible' // Internal implementation detail
444
};
445
446
return chunk.write(`<!--Context: ${JSON.stringify(debug, null, 2)}-->`);
447
};
448
449
// Usage in template: {@inspectContext/}
450
```