or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

parsing.mddocs/

0

# Template Parsing

1

2

Template parsing functionality that converts Dust template source code into Abstract Syntax Trees (AST) using a PEG.js generated parser.

3

4

## Capabilities

5

6

### Parse Function

7

8

Parses Dust template source into an Abstract Syntax Tree for compilation or analysis.

9

10

```javascript { .api }

11

/**

12

* Parses template source into Abstract Syntax Tree

13

* @param source - Dust template source code

14

* @returns Abstract Syntax Tree object representation

15

* @throws SyntaxError with detailed location information for invalid syntax

16

*/

17

function parse(source: string): ASTNode;

18

19

interface ASTNode {

20

/** Node type identifier */

21

[0]: string;

22

/** Node attributes and properties */

23

[1]?: any;

24

/** Child nodes array */

25

[2]?: ASTNode[];

26

}

27

```

28

29

**Usage Examples:**

30

31

```javascript

32

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

33

34

// Basic template parsing

35

const source = 'Hello {name}!';

36

const ast = dust.parse(source);

37

console.log(ast);

38

// Output: ['body', {}, [['buffer', 'Hello '], ['reference', ['path', ['key', 'name']], [], {}], ['buffer', '!']]]

39

40

// Complex template with sections

41

const complexSource = `

42

{#users}

43

<li>{name} - {role}</li>

44

{:else}

45

<li>No users</li>

46

{/users}

47

`;

48

49

try {

50

const complexAst = dust.parse(complexSource);

51

console.log('AST nodes:', complexAst[2].length);

52

console.log('First node type:', complexAst[2][0][0]);

53

} catch (err) {

54

console.error('Parse error:', err.message);

55

}

56

```

57

58

### AST Node Structure

59

60

Understanding the structure of parsed AST nodes for template analysis and manipulation.

61

62

```javascript { .api }

63

// Common AST node types:

64

65

// Body node (root container)

66

type BodyNode = ['body', {}, ASTNode[]];

67

68

// Buffer node (static text)

69

type BufferNode = ['buffer', string];

70

71

// Reference node (variable substitution)

72

type ReferenceNode = ['reference', PathNode, FilterNode[], ParamsNode];

73

74

// Section node (conditional/loop)

75

type SectionNode = ['section', PathNode, ContextNode, ParamsNode, BodyNode];

76

77

// Exists/NotExists nodes (conditional checks)

78

type ExistsNode = ['exists', PathNode, BodyNode];

79

type NotExistsNode = ['notexists', PathNode, BodyNode];

80

81

// Block node (template inheritance)

82

type BlockNode = ['block', KeyNode, BodyNode];

83

84

// Partial node (template inclusion)

85

type PartialNode = ['partial', PathNode | InlineNode, ContextNode, ParamsNode];

86

87

// Helper node (custom function call)

88

type HelperNode = ['helper', KeyNode, ContextNode, ParamsNode, BodyNode];

89

90

// Path node (variable path)

91

type PathNode = ['path', KeyNode[], FiltersNode[]];

92

93

// Key node (identifier)

94

type KeyNode = ['key', string];

95

96

// Inline node (literal value)

97

type InlineNode = ['inline', string];

98

```

99

100

**Usage Examples:**

101

102

```javascript

103

// Analyze AST structure

104

function analyzeTemplate(source) {

105

const ast = dust.parse(source);

106

107

function walkNodes(node, depth = 0) {

108

const indent = ' '.repeat(depth);

109

console.log(`${indent}Node: ${node[0]}`);

110

111

if (node[0] === 'reference') {

112

const path = node[1];

113

console.log(`${indent} Variable: ${path[1][0][1]}`); // Extract key name

114

}

115

116

if (node[0] === 'section') {

117

const path = node[1];

118

console.log(`${indent} Section: ${path[1][0][1]}`); // Extract section name

119

}

120

121

// Walk child nodes

122

if (node[2] && Array.isArray(node[2])) {

123

node[2].forEach(child => walkNodes(child, depth + 1));

124

}

125

}

126

127

walkNodes(ast);

128

}

129

130

// Analyze a template

131

analyzeTemplate('{#users}{name}{/users}');

132

// Output:

133

// Node: body

134

// Node: section

135

// Section: users

136

// Node: body

137

// Node: reference

138

// Variable: name

139

```

140

141

### Parser Error Handling

142

143

Comprehensive error handling with detailed location information for debugging template syntax issues.

144

145

```javascript { .api }

146

interface ParseSyntaxError extends SyntaxError {

147

/** Error message describing the syntax issue */

148

message: string;

149

/** Expected tokens or syntax elements */

150

expected: any[];

151

/** Actually found token or character */

152

found: string;

153

/** Location information for the error */

154

location: {

155

start: { offset: number; line: number; column: number };

156

end: { offset: number; line: number; column: number };

157

};

158

/** Error type name */

159

name: 'SyntaxError';

160

}

161

```

162

163

**Usage Examples:**

164

165

```javascript

166

// Handle parsing errors with location information

167

function parseWithErrorHandling(source, templateName) {

168

try {

169

return dust.parse(source);

170

} catch (err) {

171

if (err instanceof SyntaxError && err.location) {

172

console.error(`Parse error in template "${templateName}":

173

Message: ${err.message}

174

Line: ${err.location.start.line}

175

Column: ${err.location.start.column}

176

Expected: ${JSON.stringify(err.expected)}

177

Found: ${err.found}

178

Position: ${err.location.start.offset}`);

179

180

// Show source context

181

const lines = source.split('\n');

182

const errorLine = lines[err.location.start.line - 1];

183

const pointer = ' '.repeat(err.location.start.column - 1) + '^';

184

185

console.error(`Source: ${errorLine}`);

186

console.error(` ${pointer}`);

187

} else {

188

console.error('Unexpected parse error:', err);

189

}

190

throw err;

191

}

192

}

193

194

// Usage with error handling

195

try {

196

parseWithErrorHandling('{#unclosed', 'my-template');

197

} catch (err) {

198

// Error details logged above, handle appropriately

199

}

200

```

201

202

### AST Manipulation

203

204

Advanced AST manipulation for template transformation and analysis.

205

206

```javascript { .api }

207

/**

208

* Filter and transform AST nodes during compilation

209

* @param context - Compilation context

210

* @param node - AST node to filter

211

* @returns Transformed AST node

212

*/

213

function filterNode(context: any, node: ASTNode): ASTNode;

214

```

215

216

**Usage Examples:**

217

218

```javascript

219

// Custom AST transformation

220

function transformTemplate(source) {

221

// Parse to AST

222

const ast = dust.parse(source);

223

224

// Apply transformations using compiler

225

const context = {}; // Compilation context

226

const transformedAst = dust.compiler.filterNode(context, ast);

227

228

// Compile back to executable code

229

const code = dust.compiler.compileNode(context, transformedAst);

230

231

return code;

232

}

233

234

// Custom node visitor

235

function visitNodes(node, visitor) {

236

// Visit current node

237

visitor(node);

238

239

// Visit child nodes recursively

240

if (node[2] && Array.isArray(node[2])) {

241

node[2].forEach(child => visitNodes(child, visitor));

242

}

243

}

244

245

// Example: Find all variable references

246

function findReferences(source) {

247

const ast = dust.parse(source);

248

const references = [];

249

250

visitNodes(ast, (node) => {

251

if (node[0] === 'reference') {

252

const path = node[1];

253

if (path && path[1] && path[1][0] && path[1][0][1]) {

254

references.push(path[1][0][1]); // Extract variable name

255

}

256

}

257

});

258

259

return references;

260

}

261

262

// Find variables in template

263

const variables = findReferences('Hello {name}! You have {count} messages.');

264

console.log(variables); // ['name', 'count']

265

```

266

267

## Template Syntax Analysis

268

269

Understanding how different Dust template syntax elements are represented in the AST:

270

271

```javascript

272

// Variable references: {name}

273

const refAst = dust.parse('{name}');

274

// ['body', {}, [['reference', ['path', ['key', 'name']], [], {}]]]

275

276

// Sections: {#items}...{/items}

277

const sectionAst = dust.parse('{#items}Item: {name}{/items}');

278

// ['body', {}, [['section', ['path', ['key', 'items']], [...], {}]]]

279

280

// Conditionals: {?exists}...{/exists}

281

const existsAst = dust.parse('{?exists}Content{/exists}');

282

// ['body', {}, [['exists', ['path', ['key', 'exists']], [...]]]]

283

284

// Filters: {name|capitalize}

285

const filteredAst = dust.parse('{name|capitalize}');

286

// Reference node with filters array populated

287

288

// Parameters: {#section param="value"}...{/section}

289

const paramAst = dust.parse('{#section param="value"}Content{/section}');

290

// Section node with params object containing parameter definitions

291

292

// Blocks: {+title}Default Title{/title}

293

const blockAst = dust.parse('{+title}Default{/title}');

294

// ['body', {}, [['block', ['key', 'title'], [...]]]]

295

296

// Partials: {>"template" data=context /}

297

const partialAst = dust.parse('{>"template"/}');

298

// ['body', {}, [['partial', ['inline', 'template'], [...], {}]]]

299

300

// Helpers: {@helper param="value"}...{/helper}

301

const helperAst = dust.parse('{@helper param="value"}Content{/helper}');

302

// ['body', {}, [['helper', ['key', 'helper'], [...], {...}, [...]]]]

303

```

304

305

## Advanced Parser Features

306

307

### Context-Aware Parsing

308

309

The parser understands Dust template context and nesting rules:

310

311

```javascript

312

// Nested sections are properly parsed

313

const nested = dust.parse(`

314

{#users}

315

{name}

316

{#posts}

317

{title}

318

{/posts}

319

{/users}

320

`);

321

322

// Alternative section syntax

323

const alternative = dust.parse(`

324

{#users}

325

Active user: {name}

326

{:else}

327

No users found

328

{/users}

329

`);

330

331

// Complex path references

332

const paths = dust.parse('{user.profile.name} and {items[0].title}');

333

```

334

335

### Performance Considerations

336

337

The parser is optimized for template compilation performance:

338

339

- Templates are typically parsed once during compilation

340

- AST structures are lightweight for fast traversal

341

- Error reporting includes precise location information

342

- Parser supports all Dust syntax features comprehensively

343

344

```javascript

345

// For performance-critical applications, cache parsed ASTs

346

const astCache = new Map();

347

348

function getCachedAst(source, templateName) {

349

if (astCache.has(templateName)) {

350

return astCache.get(templateName);

351

}

352

353

const ast = dust.parse(source);

354

astCache.set(templateName, ast);

355

return ast;

356

}

357

```