CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-dustjs-linkedin

Asynchronous templates for the browser and server (LinkedIn fork)

Overview
Eval results
Files

context.mddocs/

Context System

Stack-based context system for data resolution with scoping, inheritance, and block management in Dust templates.

Capabilities

Context Creation

Functions for creating and managing template contexts that provide data resolution during rendering.

/**
 * Creates base template context
 * @param global - Global data object accessible throughout template
 * @param options - Context configuration options
 * @returns Context instance for template rendering
 */
function context(global: any, options?: ContextOptions): Context;

/**
 * Alias for context() function
 * @param global - Global data object
 * @param options - Context configuration options
 * @returns Context instance
 */
function makeBase(global: any, options?: ContextOptions): Context;

interface ContextOptions {
  /** Template name for debugging */
  templateName?: string;
  /** Block definitions for template inheritance */
  blocks?: { [blockName: string]: any };
  /** Additional context configuration */
  [key: string]: any;
}

Usage Examples:

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

// Basic context creation
const ctx = dust.context({
  user: { name: 'Alice', role: 'admin' },
  site: { title: 'My App', version: '1.0' }
});

// Context with options
const ctxWithOptions = dust.context({
  users: [{ name: 'Bob' }, { name: 'Carol' }]
}, {
  templateName: 'user-list',
  blocks: { header: 'Custom Header' }
});

// Using makeBase alias
const baseCtx = dust.makeBase({
  config: { debug: true },
  helpers: { customHelper: () => 'Custom' }
});

Context Type Checking

Utility function to determine if an object is a Dust context.

/**
 * Tests if object is a Dust context
 * @param obj - Object to test
 * @returns true if object is a Context instance
 */
function isContext(obj: any): boolean;

/**
 * Static method to wrap context data
 * @param context - Context data or existing Context instance
 * @param name - Template name for debugging
 * @returns Context instance
 */
Context.wrap(context: any, name?: string): Context;

Usage Examples:

const ctx = dust.context({ data: 'value' });
const plainObject = { data: 'value' };

console.log(dust.isContext(ctx)); // true
console.log(dust.isContext(plainObject)); // false

// Useful in helper functions
function myHelper(chunk, context, bodies, params) {
  if (!dust.isContext(context)) {
    throw new Error('Invalid context provided to helper');
  }
  // Helper implementation...
}

Context Instance Methods

Data Access and Resolution

Methods for accessing and resolving data within the context stack.

interface Context {
  /**
   * Get value from context by path
   * @param path - Dot-separated path or array of keys
   * @param cur - Current context data (optional)
   * @returns Resolved value or undefined
   */
  get(path: string | string[], cur?: any): any;

  /**
   * Get current context data at top of stack
   * @returns Current data object
   */
  current(): any;

  /**
   * Get template name for debugging
   * @returns Template name string or undefined
   */
  getTemplateName(): string | undefined;
}

Usage Examples:

const ctx = dust.context({
  user: {
    profile: { name: 'Alice', email: 'alice@example.com' },
    settings: { theme: 'dark', notifications: true }
  },
  items: ['apple', 'banana', 'cherry']
});

// Simple path resolution
console.log(ctx.get('user.profile.name')); // 'Alice'
console.log(ctx.get('user.settings.theme')); // 'dark'

// Array path resolution
console.log(ctx.get(['user', 'profile', 'email'])); // 'alice@example.com'

// Array index access
console.log(ctx.get('items.0')); // 'apple'
console.log(ctx.get('items.2')); // 'cherry'

// Non-existent path
console.log(ctx.get('user.invalid.path')); // undefined

// Current context data
console.log(ctx.current()); // Full context object

Context Stack Management

Methods for manipulating the context stack during template execution.

interface Context {
  /**
   * Push new data onto context stack
   * @param head - New context data to push
   * @param idx - Index for array iterations (optional)
   * @param len - Length for array iterations (optional)
   * @returns New context with pushed data
   */
  push(head: any, idx?: number, len?: number): Context;

  /**
   * Remove top item from context stack
   * @returns Context with popped data
   */
  pop(): Context;

  /**
   * Create new context with different base data
   * @param head - New base data
   * @returns New context instance
   */
  rebase(head: any): Context;

  /**
   * Clone current context
   * @returns New context instance with same data
   */
  clone(): Context;
}

Usage Examples:

const baseCtx = dust.context({
  global: 'value',
  config: { debug: true }
});

// Push new context data
const userCtx = baseCtx.push({
  name: 'Bob',
  role: 'editor'
});

console.log(userCtx.get('name')); // 'Bob' (from pushed data)
console.log(userCtx.get('global')); // 'value' (from base context)

// Push with array iteration info
const items = ['a', 'b', 'c'];
items.forEach((item, idx) => {
  const itemCtx = baseCtx.push(item, idx, items.length);
  console.log(itemCtx.get('@index')); // Current index
  console.log(itemCtx.get('@length')); // Array length
});

// Pop context
const poppedCtx = userCtx.pop();
console.log(poppedCtx.get('name')); // undefined (popped)
console.log(poppedCtx.get('global')); // 'value' (still available)

// Rebase context
const rebasedCtx = baseCtx.rebase({
  newBase: 'data',
  different: 'values'
});

// Clone context
const clonedCtx = baseCtx.clone();
console.log(clonedCtx.get('global')); // 'value'

Block Management

Methods for managing template blocks used in template inheritance.

interface Context {
  /**
   * Get block by name
   * @param key - Block name
   * @returns Block definition or undefined
   */
  getBlock(key: string): any;

  /**
   * Add local blocks to context
   * @param locals - Object containing block definitions
   * @returns New context with added blocks
   */
  shiftBlocks(locals: { [blockName: string]: any }): Context;
}

Usage Examples:

// Context with blocks
const ctx = dust.context({ data: 'value' }, {
  blocks: {
    header: 'Custom Header Block',
    footer: 'Custom Footer Block'
  }
});

// Get block by name
console.log(ctx.getBlock('header')); // 'Custom Header Block'
console.log(ctx.getBlock('sidebar')); // undefined

// Add local blocks
const extendedCtx = ctx.shiftBlocks({
  sidebar: 'Sidebar Block',
  navigation: 'Nav Block'
});

console.log(extendedCtx.getBlock('sidebar')); // 'Sidebar Block'
console.log(extendedCtx.getBlock('header')); // 'Custom Header Block' (inherited)

Template Body Resolution

Method for resolving template bodies to string output.

interface Context {
  /**
   * Resolve template body to string output
   * @param body - Template body function or content
   * @returns Promise resolving to rendered string
   */
  resolve(body: any): Promise<string>;
}

Usage Examples:

// Used internally by Dust during template rendering
// Typically not called directly by user code
const ctx = dust.context({ name: 'Alice' });

// In a helper function
function customHelper(chunk, context, bodies, params) {
  if (bodies.block) {
    return context.resolve(bodies.block).then(content => {
      return chunk.write(`<div class="wrapper">${content}</div>`);
    });
  }
  return chunk;
}

Context Data Resolution

Path Resolution Rules

Understanding how Dust resolves data paths within the context stack:

const ctx = dust.context({
  // Global data
  global: 'global-value',
  user: { name: 'Alice' }
}).push({
  // Local data (top of stack)
  local: 'local-value',
  user: { role: 'admin' }  // Shadows global user
});

// Resolution priority (top of stack first)
console.log(ctx.get('local'));      // 'local-value' (local only)
console.log(ctx.get('global'));     // 'global-value' (global only)
console.log(ctx.get('user.name'));  // undefined (local user has no name)
console.log(ctx.get('user.role'));  // 'admin' (local user.role)

// Explicit current context access
console.log(ctx.current().local);   // 'local-value'

Special Context Variables

Dust provides special variables during iterations and template execution:

// Array iteration provides special variables
const items = ['apple', 'banana', 'cherry'];
const ctx = dust.context({ items });

// When iterating over array (internally handled by sections)
items.forEach((item, idx) => {
  const iterCtx = ctx.push(item, idx, items.length);

  console.log(iterCtx.get('@index'));    // Current index (0, 1, 2)
  console.log(iterCtx.get('@length'));   // Array length (3)
  console.log(iterCtx.get('@first'));    // true for first item
  console.log(iterCtx.get('@last'));     // true for last item
  console.log(iterCtx.get('@odd'));      // true for odd indices
  console.log(iterCtx.get('@even'));     // true for even indices
});

// Object iteration provides key access
const obj = { a: 1, b: 2, c: 3 };
Object.keys(obj).forEach((key, idx) => {
  const iterCtx = ctx.push(obj[key], idx, Object.keys(obj).length);
  iterCtx.key = key; // Key is available as property

  console.log(iterCtx.get('@key'));      // Current key ('a', 'b', 'c')
  console.log(iterCtx.get('.'));         // Current value (1, 2, 3)
});

Advanced Context Usage

Context in Helper Functions

How context is used within helper functions:

// Register a helper that uses context
dust.helpers.debugContext = (chunk, context, bodies, params) => {
  // Access current data
  const currentData = context.current();

  // Get specific values
  const userName = context.get('user.name');
  const templateName = context.getTemplateName();

  // Push new context for body execution
  const newContext = context.push({
    debug: true,
    timestamp: Date.now()
  });

  // Render body with new context
  return chunk.render(bodies.block, newContext);
};

// Usage in template: {@debugContext}Content with debug info{/debugContext}

Context Performance Considerations

Best practices for efficient context usage:

// Efficient: Reuse base contexts
const baseCtx = dust.context({
  config: appConfig,
  helpers: customHelpers
});

// For each render, push specific data
function renderUserTemplate(userData) {
  const userCtx = baseCtx.push(userData);
  return dust.render('user-template', userCtx, callback);
}

// Avoid: Creating new base contexts repeatedly
function inefficientRender(userData) {
  const ctx = dust.context({
    config: appConfig,  // Recreated each time
    ...userData
  });
  return dust.render('user-template', ctx, callback);
}

Context Debugging

Utilities for debugging context resolution:

// Debug helper to inspect context
dust.helpers.inspectContext = (chunk, context) => {
  const debug = {
    current: context.current(),
    templateName: context.getTemplateName(),
    stackDepth: 'not directly accessible' // Internal implementation detail
  };

  return chunk.write(`<!--Context: ${JSON.stringify(debug, null, 2)}-->`);
};

// Usage in template: {@inspectContext/}

Install with Tessl CLI

npx tessl i tessl/npm-dustjs-linkedin

docs

cli.md

compilation.md

context.md

filters.md

helpers.md

index.md

parsing.md

rendering.md

tile.json