or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

commit-pipeline.mdfile-copy.mdfile-management.mdfile-reading.mdfile-writing.mdindex.mdstate-management.mdtemplate-processing.mdtransform.md

template-processing.mddocs/

0

# Template Processing

1

2

EJS template processing for dynamic file generation with context variables and template options, enabling creation of customized files from templates.

3

4

## Capabilities

5

6

### Copy with Template Processing

7

8

Copy files and process them as EJS templates, substituting variables with provided context data.

9

10

```typescript { .api }

11

/**

12

* Copy files with EJS template processing

13

* @param from - Source template files or glob pattern

14

* @param to - Destination path

15

* @param context - Template variables for substitution

16

* @param tplSettings - EJS template configuration options

17

* @param options - Copy options

18

*/

19

function copyTpl(

20

from: string | string[],

21

to: string,

22

context?: Record<string, any>,

23

tplSettings?: EJSOptions,

24

options?: CopySingleOptions

25

): void;

26

27

interface EJSOptions {

28

/** Template filename for error reporting */

29

filename?: string;

30

/** Enable template caching for performance */

31

cache?: boolean;

32

/** Custom opening delimiter (default: "<%") */

33

openDelimiter?: string;

34

/** Custom closing delimiter (default: "%>") */

35

closeDelimiter?: string;

36

/** Additional EJS configuration options */

37

[key: string]: any;

38

}

39

40

interface CopySingleOptions {

41

/** Append to destination instead of overwriting */

42

append?: boolean;

43

/** Process file contents during copy */

44

process?: (contents: string | Buffer, filepath: string, destination: string) => string | Buffer;

45

}

46

```

47

48

**Usage Examples:**

49

50

```typescript

51

import { create as createMemFs } from "mem-fs";

52

import { create as createEditor } from "mem-fs-editor";

53

54

const store = createMemFs();

55

const fs = createEditor(store);

56

57

// Basic template processing

58

const context = {

59

name: "MyProject",

60

version: "1.0.0",

61

author: "John Doe"

62

};

63

64

fs.copyTpl("templates/package.json.ejs", "package.json", context);

65

66

// Note: .ejs extensions are automatically removed from destination paths

67

fs.copyTpl("template.txt.ejs", "output/", context);

68

// Creates: output/template.txt (not output/template.txt.ejs)

69

70

// Multiple template files

71

fs.copyTpl("templates/**/*.ejs", "output/", {

72

projectName: "awesome-app",

73

features: ["auth", "database", "api"],

74

config: {

75

port: 3000,

76

database: "mongodb"

77

}

78

});

79

80

// Template with custom delimiters

81

fs.copyTpl("template.txt", "output.txt", { name: "World" }, {

82

openDelimiter: "{{",

83

closeDelimiter: "}}"

84

});

85

```

86

87

### Async Template Copy

88

89

Asynchronous template processing for better performance with large template sets.

90

91

```typescript { .api }

92

/**

93

* Async version of template copy

94

* @param from - Source template files or glob pattern

95

* @param to - Destination path

96

* @param context - Template variables for substitution

97

* @param tplSettings - EJS template configuration options

98

* @param options - Copy options

99

* @returns Promise that resolves when template processing is complete

100

*/

101

function copyTplAsync(

102

from: string | string[],

103

to: string,

104

context?: Record<string, any>,

105

tplSettings?: EJSOptions,

106

options?: CopySingleOptions

107

): Promise<void>;

108

```

109

110

**Usage Examples:**

111

112

```typescript

113

// Async template processing

114

await fs.copyTplAsync("templates/**/*.ejs", "generated/", {

115

timestamp: new Date().toISOString(),

116

environment: "production",

117

features: {

118

authentication: true,

119

logging: true,

120

monitoring: false

121

}

122

});

123

124

// Process large template sets

125

const contexts = [

126

{ name: "frontend", type: "react" },

127

{ name: "backend", type: "node" },

128

{ name: "database", type: "postgres" }

129

];

130

131

for (const ctx of contexts) {

132

await fs.copyTplAsync(`templates/${ctx.type}/**/*.ejs`, `services/${ctx.name}/`, ctx);

133

}

134

```

135

136

### Append Template Content

137

138

Append templated content to existing files, useful for building up files incrementally.

139

140

```typescript { .api }

141

/**

142

* Append templated content to file

143

* @param filepath - Target file path

144

* @param contents - Template content string

145

* @param context - Template variables for substitution

146

* @param templateOptions - EJS template settings

147

* @param options - Append configuration options

148

*/

149

function appendTpl(

150

filepath: string,

151

contents: string,

152

context: Record<string, any>,

153

templateOptions?: EJSOptions,

154

options?: AppendOptions

155

): void;

156

157

interface AppendOptions {

158

/** Create file if it doesn't exist (default: true) */

159

create?: boolean;

160

/** Remove trailing whitespace before appending (default: false) */

161

trimEnd?: boolean;

162

/** Separator to add between existing and new content */

163

separator?: string;

164

}

165

```

166

167

**Usage Examples:**

168

169

```typescript

170

// Build up a file with multiple template appends

171

const baseContext = { projectName: "MyApp" };

172

173

// Initialize file

174

fs.write("config.js", "// Generated configuration\n");

175

176

// Append database config

177

fs.appendTpl("config.js", `

178

const database = {

179

host: '<%= host %>',

180

port: <%= port %>,

181

name: '<%= dbName %>'

182

};

183

`, {

184

host: "localhost",

185

port: 5432,

186

dbName: baseContext.projectName.toLowerCase()

187

}, null, { separator: "\n" });

188

189

// Append server config

190

fs.appendTpl("config.js", `

191

const server = {

192

port: <%= serverPort %>,

193

env: '<%= environment %>'

194

};

195

`, {

196

serverPort: 3000,

197

environment: "development"

198

}, null, { separator: "\n" });

199

```

200

201

### Internal Template Processing

202

203

Direct template processing function for custom workflows.

204

205

```typescript { .api }

206

/**

207

* Process file contents as EJS template

208

* @param params - Template processing parameters

209

* @returns Processed template content

210

*/

211

function _processTpl(params: {

212

contents: string | Buffer;

213

filename: string;

214

context?: Record<string, any>;

215

tplSettings?: EJSOptions;

216

}): string;

217

```

218

219

**Usage Examples:**

220

221

```typescript

222

// Process template content directly

223

const templateContent = `

224

Hello <%= name %>!

225

Your project <%= projectName %> is ready.

226

Features: <% features.forEach(feature => { %>

227

- <%= feature %>

228

<% }); %>

229

`;

230

231

const processed = fs._processTpl({

232

contents: templateContent,

233

filename: "greeting.txt",

234

context: {

235

name: "Developer",

236

projectName: "AwesomeApp",

237

features: ["Authentication", "Database", "API"]

238

}

239

});

240

241

fs.write("output.txt", processed);

242

```

243

244

## Template Syntax and Examples

245

246

### Basic Variable Substitution

247

248

```ejs

249

<!-- Template: greeting.ejs -->

250

Hello <%= name %>!

251

Welcome to <%= projectName %>.

252

```

253

254

```typescript

255

// Usage

256

fs.copyTpl("greeting.ejs", "greeting.txt", {

257

name: "Alice",

258

projectName: "Amazing App"

259

});

260

// Output: "Hello Alice!\nWelcome to Amazing App."

261

```

262

263

### Conditional Content

264

265

```ejs

266

<!-- Template: config.ejs -->

267

{

268

"name": "<%= name %>",

269

"version": "<%= version %>"<% if (features.includes('auth')) { %>,

270

"authentication": {

271

"provider": "<%= authProvider || 'local' %>"

272

}<% } %><% if (features.includes('database')) { %>,

273

"database": {

274

"type": "<%= dbType || 'sqlite' %>"

275

}<% } %>

276

}

277

```

278

279

```typescript

280

fs.copyTpl("config.ejs", "config.json", {

281

name: "my-app",

282

version: "1.0.0",

283

features: ["auth", "database"],

284

authProvider: "oauth2",

285

dbType: "postgresql"

286

});

287

```

288

289

### Loops and Iteration

290

291

```ejs

292

<!-- Template: routes.ejs -->

293

<% routes.forEach(route => { %>

294

app.<%= route.method %>('<%= route.path %>', <%= route.handler %>);

295

<% }); %>

296

297

<!-- Generated imports -->

298

<% dependencies.forEach(dep => { %>

299

const <%= dep.name %> = require('<%= dep.package %>');

300

<% }); %>

301

```

302

303

```typescript

304

fs.copyTpl("routes.ejs", "routes.js", {

305

routes: [

306

{ method: "get", path: "/users", handler: "getUsersHandler" },

307

{ method: "post", path: "/users", handler: "createUserHandler" },

308

{ method: "delete", path: "/users/:id", handler: "deleteUserHandler" }

309

],

310

dependencies: [

311

{ name: "express", package: "express" },

312

{ name: "cors", package: "cors" }

313

]

314

});

315

```

316

317

### Complex Context Objects

318

319

```typescript

320

// Complex template context

321

const context = {

322

project: {

323

name: "e-commerce-api",

324

version: "2.1.0",

325

description: "REST API for e-commerce platform"

326

},

327

database: {

328

type: "postgresql",

329

host: "localhost",

330

port: 5432,

331

ssl: false

332

},

333

features: {

334

authentication: { enabled: true, provider: "jwt" },

335

logging: { enabled: true, level: "info" },

336

monitoring: { enabled: false }

337

},

338

endpoints: [

339

{ path: "/api/products", methods: ["GET", "POST"] },

340

{ path: "/api/orders", methods: ["GET", "POST", "PUT"] },

341

{ path: "/api/users", methods: ["GET", "POST", "DELETE"] }

342

]

343

};

344

345

fs.copyTpl("templates/**/*.ejs", "generated/", context);

346

```

347

348

## Error Handling and Debugging

349

350

```typescript

351

// Template processing with error handling

352

try {

353

fs.copyTpl("template.ejs", "output.txt", context, {

354

filename: "template.ejs" // Helps with error reporting

355

});

356

} catch (error) {

357

if (error.message.includes("ReferenceError")) {

358

console.error("Template variable not found:", error.message);

359

} else {

360

console.error("Template processing failed:", error.message);

361

}

362

}

363

364

// Debug template context

365

const debugContext = {

366

...context,

367

_debug: true,

368

_timestamp: new Date().toISOString()

369

};

370

371

fs.copyTpl("debug-template.ejs", "debug-output.txt", debugContext);

372

```

373

374

## Custom Delimiters

375

376

```typescript

377

// Use custom delimiters for templates that conflict with default EJS syntax

378

fs.copyTpl("template.txt", "output.txt", { name: "World" }, {

379

openDelimiter: "{{",

380

closeDelimiter: "}}"

381

});

382

383

// Template content with custom delimiters:

384

// "Hello {{ name }}! Today is {{ new Date().toDateString() }}."

385

```