node-tao 0.0.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/tao.js CHANGED
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Tao = void 0;
7
7
  const default_config_1 = require("./default-config");
8
- const checks_1 = require("./checks");
8
+ const validations_1 = require("./validations");
9
9
  const templates_access_1 = require("./templates-access");
10
10
  const node_fs_1 = __importDefault(require("node:fs"));
11
11
  const utils_1 = require("./utils");
@@ -16,38 +16,40 @@ const node_path_1 = __importDefault(require("node:path"));
16
16
  const node_perf_hooks_1 = require("node:perf_hooks");
17
17
  const metrics_1 = require("./metrics");
18
18
  const init_1 = require("./init");
19
- const parsing_helpers_1 = require("./parsing-helpers");
20
19
  class Tao {
20
+ config;
21
+ templatePaths = [];
22
+ /**
23
+ * Stores already compiled templates.
24
+ */
25
+ compiledStore = new store_1.Store();
26
+ /**
27
+ * Stores dynamically loaded templates.
28
+ */
29
+ dynamictemplatesStore = new store_1.Store();
30
+ /**
31
+ * Stores global helpers.
32
+ */
33
+ helpersStore = new store_1.Store();
34
+ /**
35
+ * Metrics - DX
36
+ */
37
+ parentTemplate = '';
38
+ /**
39
+ * Metrics - DX
40
+ */
41
+ childrenStore = new store_1.Store();
21
42
  constructor(customConfig = {}) {
22
- this.templatePaths = [];
23
- this.prefixBuild = '';
24
- /**
25
- * Stores already compiled templates.
26
- */
27
- this.compiledStore = new store_1.Store();
28
- /**
29
- * Stores dynamically loaded templates.
30
- */
31
- this.dynamictemplatesStore = new store_1.Store();
32
- /**
33
- * Stores global helpers.
34
- */
35
- this.helpersStore = new store_1.Store();
36
- // Metrics - DX
37
- this.parentTemplate = '';
38
- // Metrics - DX
39
- this.childrenStore = new store_1.Store();
40
- this.config = Object.assign(Object.assign({}, default_config_1.defaultConfig), customConfig);
43
+ this.config = { ...default_config_1.defaultConfig, ...customConfig };
41
44
  this.initializeConfig();
42
45
  }
43
46
  initializeConfig() {
44
47
  const { views, extension, tags, parse } = this.config;
45
48
  this.config.tags = (0, init_1.assignTags)(tags);
46
49
  this.config.parse = (0, init_1.assignParse)(parse);
47
- this.config.extension = (0, checks_1.trimDotFromExtension)(extension);
48
- (0, checks_1.checkOpeningAndClosingTag)(this.config.tags);
49
- (0, checks_1.checkPrefixTemplateTags)(this.config.parse);
50
- this.prefixBuild = (0, utils_1.buildPrefixRegex)(this.config.parse);
50
+ this.config.extension = (0, validations_1.trimDotFromExtension)(extension);
51
+ (0, validations_1.checkOpeningAndClosingTag)(this.config.tags);
52
+ (0, validations_1.checkPrefixTemplateTags)(this.config.parse);
51
53
  this.templatePaths = (0, templates_access_1.getFilesFromDirectory)(views, this.config.extension);
52
54
  }
53
55
  /**
@@ -66,8 +68,8 @@ class Tao {
66
68
  };
67
69
  return metricsData;
68
70
  }
69
- compileChild(content, debugData) {
70
- const compiledAST = this.parse(content, debugData);
71
+ compileChild(content) {
72
+ const compiledAST = this.templateLexer(content);
71
73
  const result = `
72
74
  ${(0, utils_1.includeFn)()}
73
75
 
@@ -82,9 +84,9 @@ class Tao {
82
84
  `;
83
85
  return result;
84
86
  }
85
- compile(content, filename, debugData) {
87
+ compile(content, filename) {
86
88
  const { development } = this.config;
87
- const compiledAST = this.parse(content, debugData);
89
+ const compiledAST = this.templateLexer(content);
88
90
  this.childrenStore.set(this.parentTemplate, []);
89
91
  const metricsData = this.getMetrics(filename);
90
92
  const result = `
@@ -106,83 +108,201 @@ class Tao {
106
108
  `;
107
109
  return result;
108
110
  }
109
- parse(expression, debugData) {
111
+ /**
112
+ * A basic lexer covering most of the edge cases (quotes, comments, template literals, nested templates, etc.) to parse the template into an array of TemplateData containing the line information, start and end positions.
113
+ */
114
+ templateLexer(rawExpression) {
110
115
  const { parse, tags } = this.config;
111
- const { closing, opening } = tags;
112
- let openingResult = null;
113
- const compiledData = [];
114
- let lastIndex = 0;
115
- const parseOpenReg = new RegExp((0, utils_1.escapeRegExp)(opening) + '\\s*(' + this.prefixBuild + ')?\\s*', 'g');
116
- const parseCloseReg = new RegExp('\'|"|`|(\\s*' + (0, utils_1.escapeRegExp)(closing) + ')', 'g');
117
- while ((openingResult = parseOpenReg.exec(expression))) {
118
- // openingPrefix by default either ~, =, or empty
119
- const [originalOpen, openingPrefix = ''] = openingResult;
120
- let closeResult = null;
121
- let templateData = undefined;
122
- const precedingExpression = expression.slice(lastIndex, openingResult.index);
123
- lastIndex = originalOpen.length + openingResult.index;
124
- const escapedExpression = (0, utils_1.escapeJSLiteral)(precedingExpression);
125
- compiledData.push(escapedExpression);
126
- parseCloseReg.lastIndex = lastIndex;
127
- while ((closeResult = parseCloseReg.exec(expression))) {
128
- const [originalClose, closePrefix] = closeResult;
129
- if (closePrefix) {
130
- const content = expression.slice(lastIndex, closeResult.index);
131
- lastIndex = parseCloseReg.lastIndex;
132
- parseOpenReg.lastIndex = lastIndex;
133
- const contentLiteralEscaped = (0, utils_1.replaceCarriageReturn)(content);
134
- const currentType = (0, utils_1.getCurrentPrefixType)(openingPrefix, parse);
135
- templateData = { type: currentType, content: contentLiteralEscaped };
136
- compiledData.push(templateData);
116
+ const { opening, closing } = tags;
117
+ const errorType = 'Parse Error';
118
+ const tokens = [];
119
+ let index = 0;
120
+ let line = 1;
121
+ const openingLength = opening.length;
122
+ const closingLength = closing.length;
123
+ const updatePosition = (char) => {
124
+ if (char === '\n')
125
+ line++;
126
+ };
127
+ while (index < rawExpression.length) {
128
+ const openIndex = rawExpression.indexOf(opening, index);
129
+ // Text after the last opening tag
130
+ if (openIndex === -1) {
131
+ const text = rawExpression.slice(index);
132
+ tokens.push({
133
+ type: null,
134
+ value: (0, utils_1.escapeJSLiteral)(text),
135
+ line,
136
+ startPos: index,
137
+ endPos: rawExpression.length,
138
+ });
139
+ break;
140
+ }
141
+ // Text before an opening tag
142
+ if (openIndex > index) {
143
+ const text = rawExpression.slice(index, openIndex);
144
+ if (text.length > 0) {
145
+ tokens.push({
146
+ type: null,
147
+ value: (0, utils_1.escapeJSLiteral)(text),
148
+ line,
149
+ startPos: index,
150
+ endPos: openIndex,
151
+ });
152
+ }
153
+ }
154
+ // advance position until openIndex
155
+ while (index < openIndex) {
156
+ updatePosition(rawExpression[index]);
157
+ index++;
158
+ }
159
+ const blockLine = line;
160
+ let cursor = openIndex + openingLength;
161
+ const mode = (0, utils_1.getCurrentPrefixType)(rawExpression[cursor].trim(), parse);
162
+ if (mode !== null) {
163
+ cursor++;
164
+ }
165
+ const contentStart = cursor;
166
+ let inSingle = false;
167
+ let inDouble = false;
168
+ let inBacktick = false;
169
+ let inLineComment = false;
170
+ let inBlockComment = false;
171
+ let escaped = false;
172
+ let singleQuoteStart = null;
173
+ let doubleQuoteStart = null;
174
+ let backtickStart = null;
175
+ let blockCommentStart = null;
176
+ while (cursor < rawExpression.length) {
177
+ const char = rawExpression[cursor];
178
+ const next = rawExpression[cursor + 1];
179
+ updatePosition(char);
180
+ if (escaped) {
181
+ escaped = false;
182
+ cursor++;
183
+ continue;
184
+ }
185
+ if (char === '\\') {
186
+ escaped = true;
187
+ cursor++;
188
+ continue;
189
+ }
190
+ if (inLineComment) {
191
+ if (char === '\n')
192
+ inLineComment = false;
193
+ cursor++;
194
+ continue;
195
+ }
196
+ if (inBlockComment) {
197
+ if (char === '*' && next === '/') {
198
+ inBlockComment = false;
199
+ blockCommentStart = null;
200
+ cursor += 2;
201
+ continue;
202
+ }
203
+ cursor++;
204
+ continue;
205
+ }
206
+ if (!inSingle && !inDouble && !inBacktick) {
207
+ if (char === '/' && next === '/') {
208
+ inLineComment = true;
209
+ cursor += 2;
210
+ continue;
211
+ }
212
+ if (char === '/' && next === '*') {
213
+ inBlockComment = true;
214
+ blockCommentStart = { line };
215
+ cursor += 2;
216
+ continue;
217
+ }
218
+ }
219
+ if (!inDouble && !inBacktick && char === "'") {
220
+ inSingle = !inSingle;
221
+ singleQuoteStart = inSingle ? { line } : null;
222
+ cursor++;
223
+ continue;
224
+ }
225
+ if (!inSingle && !inBacktick && char === '"') {
226
+ inDouble = !inDouble;
227
+ doubleQuoteStart = inDouble ? { line } : null;
228
+ cursor++;
229
+ continue;
230
+ }
231
+ if (!inSingle && !inDouble && char === '`') {
232
+ inBacktick = !inBacktick;
233
+ backtickStart = inBacktick ? { line } : null;
234
+ cursor++;
235
+ continue;
236
+ }
237
+ if (!inSingle &&
238
+ !inDouble &&
239
+ !inBacktick &&
240
+ !inLineComment &&
241
+ !inBlockComment &&
242
+ rawExpression.startsWith(closing, cursor)) {
137
243
  break;
138
244
  }
139
- parseCloseReg.lastIndex = (0, parsing_helpers_1.handleQuotes)(expression, originalClose, closeResult.index, debugData.fileContent);
245
+ cursor++;
246
+ }
247
+ if (inSingle) {
248
+ const error = (0, error_utils_1.buildErrorData)('Unclosed single quote', singleQuoteStart.line, rawExpression, errorType);
249
+ throw error;
140
250
  }
141
- (0, parsing_helpers_1.checkForUnclosedPrefix)(templateData, expression, originalOpen, openingResult.index, debugData.fileContent);
251
+ if (inDouble) {
252
+ const error = (0, error_utils_1.buildErrorData)('Unclosed double quote', doubleQuoteStart.line, rawExpression, errorType);
253
+ throw error;
254
+ }
255
+ if (inBacktick) {
256
+ const error = (0, error_utils_1.buildErrorData)('Unclosed backtick', backtickStart.line, rawExpression, errorType);
257
+ throw error;
258
+ }
259
+ if (inBlockComment) {
260
+ const error = (0, error_utils_1.buildErrorData)('Unclosed block comment', blockCommentStart.line, rawExpression, errorType);
261
+ throw error;
262
+ }
263
+ if (cursor >= rawExpression.length) {
264
+ const error = (0, error_utils_1.buildErrorData)(`Unclosed template block ${closing}`, line, rawExpression, errorType);
265
+ throw error;
266
+ }
267
+ const content = rawExpression.slice(contentStart, cursor).trim();
268
+ tokens.push({
269
+ type: mode,
270
+ value: content,
271
+ line: blockLine,
272
+ startPos: contentStart,
273
+ endPos: cursor,
274
+ });
275
+ index = cursor + closingLength;
142
276
  }
143
- const endOfTemplate = expression.slice(lastIndex);
144
- const escapedEndOfTemplate = (0, utils_1.escapeJSLiteral)(endOfTemplate);
145
- compiledData.push(escapedEndOfTemplate);
146
- return compiledData;
277
+ return tokens;
147
278
  }
148
279
  /**
149
280
  * Render a template with data and helpers.
150
281
  * @param template The path of your template to render.
151
- * @param data The variables to inject.
152
- * @param helpers The helpers functions to inject.
282
+ * @param dataOrHelpers The variables and helpers to inject.
153
283
  */
154
- render(template, data = {}, helpers = {}) {
284
+ render(template, dataOrHelpers = {}) {
155
285
  const debugData = (0, init_1.initDebugData)();
156
286
  if (typeof template !== 'string') {
157
287
  const error = (0, error_utils_1.handleWrongTypeOfTemplate)(template);
158
288
  const { errorHTML } = this.manageError(error, template, debugData);
159
289
  return errorHTML;
160
290
  }
161
- const { views, extension, fileResolution, development } = this.config;
291
+ const { views, extension, fileResolution } = this.config;
162
292
  const ɵɵstart = node_perf_hooks_1.performance.now();
163
293
  let ɵɵcacheHit = false;
164
- const pathWithExtension = (0, checks_1.getPathWithExtension)(template, extension);
294
+ const pathWithExtension = (0, validations_1.getPathWithExtension)(template, extension);
165
295
  const filename = (0, utils_1.getFileName)(pathWithExtension);
166
296
  const fullPath = (0, utils_1.getResolvedPath)(views, pathWithExtension, fileResolution);
167
297
  this.parentTemplate = filename;
168
298
  this.childrenStore.remove(this.parentTemplate);
169
- const injectedData = {
170
- development,
171
- fullPath,
172
- data,
173
- helpers,
174
- helpersStore: this.helpersStore,
175
- templatePaths: this.templatePaths,
176
- };
177
- (0, utils_1.injectUserDataForVSCodeExtension)(injectedData);
178
- if ((0, checks_1.isTemplateDynamicallyDefined)(template)) {
299
+ if ((0, validations_1.isTemplateDynamicallyDefined)(template)) {
179
300
  const cachedTemplate = this.compiledStore.get(template);
180
301
  if (cachedTemplate) {
181
302
  ɵɵcacheHit = true;
182
303
  const executeData = {
183
304
  compiledContent: cachedTemplate,
184
- data,
185
- helpers,
305
+ dataOrHelpers,
186
306
  ɵɵstart,
187
307
  filename: template,
188
308
  ɵɵcacheHit,
@@ -197,8 +317,7 @@ class Tao {
197
317
  }
198
318
  const templateData = {
199
319
  templateLoaded,
200
- data,
201
- helpers,
320
+ dataOrHelpers,
202
321
  ɵɵstart,
203
322
  filename: template,
204
323
  ɵɵcacheHit,
@@ -211,7 +330,7 @@ class Tao {
211
330
  return errorHTML;
212
331
  }
213
332
  const files = (0, templates_access_1.checkAccessPermission)(this.templatePaths, fullPath);
214
- if (!(0, templates_access_1.fileIsUnique)(files)) {
333
+ if (files.length !== 1) {
215
334
  const error = (0, error_utils_1.handleNonUniqueFile)(files, filename);
216
335
  const { errorHTML } = this.manageError(error, filename, debugData);
217
336
  return errorHTML;
@@ -221,8 +340,7 @@ class Tao {
221
340
  ɵɵcacheHit = true;
222
341
  const executeData = {
223
342
  compiledContent: cachedTemplate,
224
- data,
225
- helpers,
343
+ dataOrHelpers,
226
344
  ɵɵstart,
227
345
  filename,
228
346
  ɵɵcacheHit,
@@ -234,8 +352,7 @@ class Tao {
234
352
  const compileData = {
235
353
  filename,
236
354
  fullPath: file,
237
- data,
238
- helpers,
355
+ dataOrHelpers,
239
356
  ɵɵstart,
240
357
  ɵɵcacheHit,
241
358
  };
@@ -244,34 +361,24 @@ class Tao {
244
361
  /**
245
362
  * Render a child component. Called inside the parent template.
246
363
  */
247
- renderChild(template, data = {}, helpers = {}) {
364
+ renderChild(template, dataOrHelpers = {}) {
248
365
  const debugData = (0, init_1.initDebugData)();
249
366
  if (typeof template !== 'string') {
250
367
  const error = (0, error_utils_1.handleWrongTypeOfTemplate)(template);
251
368
  const errorData = this.handleChildError(error, template, debugData);
252
369
  return errorData;
253
370
  }
254
- const { views, extension, fileResolution, development } = this.config;
255
- const pathWithExtension = (0, checks_1.getPathWithExtension)(template, extension);
371
+ const { views, extension, fileResolution } = this.config;
372
+ const pathWithExtension = (0, validations_1.getPathWithExtension)(template, extension);
256
373
  const filename = (0, utils_1.getFileName)(pathWithExtension);
257
374
  const fullPath = (0, utils_1.getResolvedPath)(views, pathWithExtension, fileResolution);
258
375
  (0, metrics_1.updateChildrenStore)(this.childrenStore, filename, this.parentTemplate, this.config.development);
259
- const injectedData = {
260
- development,
261
- fullPath,
262
- data,
263
- helpers,
264
- helpersStore: this.helpersStore,
265
- templatePaths: this.templatePaths,
266
- };
267
- (0, utils_1.injectUserDataForVSCodeExtension)(injectedData);
268
- if ((0, checks_1.isTemplateDynamicallyDefined)(template)) {
376
+ if ((0, validations_1.isTemplateDynamicallyDefined)(template)) {
269
377
  const cachedTemplate = this.compiledStore.get(template);
270
378
  if (cachedTemplate) {
271
379
  const executeData = {
272
380
  compiledContent: cachedTemplate,
273
- data,
274
- helpers,
381
+ dataOrHelpers,
275
382
  filename: template,
276
383
  };
277
384
  return this.executeChildFunction(executeData, debugData);
@@ -284,14 +391,13 @@ class Tao {
284
391
  }
285
392
  const templateData = {
286
393
  templateLoaded,
287
- data,
288
- helpers,
394
+ dataOrHelpers,
289
395
  filename: template,
290
396
  };
291
397
  return this.handleLoadedChildTemplate(templateData, debugData);
292
398
  }
293
399
  const files = (0, templates_access_1.checkAccessPermission)(this.templatePaths, fullPath);
294
- if (!(0, templates_access_1.fileIsUnique)(files)) {
400
+ if (files.length !== 1) {
295
401
  const error = (0, error_utils_1.handleNonUniqueFile)(files, filename);
296
402
  const errorData = this.handleChildError(error, filename, debugData);
297
403
  return errorData;
@@ -300,8 +406,7 @@ class Tao {
300
406
  if (cachedTemplate) {
301
407
  const executeData = {
302
408
  compiledContent: cachedTemplate,
303
- data,
304
- helpers,
409
+ dataOrHelpers,
305
410
  filename,
306
411
  };
307
412
  return this.executeChildFunction(executeData, debugData);
@@ -310,17 +415,16 @@ class Tao {
310
415
  const compileData = {
311
416
  filename,
312
417
  fullPath: file,
313
- data,
314
- helpers,
418
+ dataOrHelpers,
315
419
  };
316
420
  return this.compileAndExecuteChild(compileData, debugData);
317
421
  }
318
422
  compileAndExecuteChild(compileData, debugData) {
319
- const { data, filename, fullPath, helpers } = compileData;
423
+ const { dataOrHelpers, filename, fullPath } = compileData;
320
424
  try {
321
- const templateFn = this.readChildFileAndGetCompiledFn(fullPath, data, helpers, filename, debugData);
322
- const immutableData = structuredClone(data);
323
- const html = templateFn.call(this, immutableData, helpers);
425
+ const templateFn = this.readChildFileAndGetCompiledFn(fullPath, dataOrHelpers, filename, debugData);
426
+ const { data, helpers } = (0, utils_1.cloneData)(dataOrHelpers);
427
+ const html = templateFn.call(this, data, helpers);
324
428
  return html;
325
429
  }
326
430
  catch (error) {
@@ -329,11 +433,11 @@ class Tao {
329
433
  }
330
434
  }
331
435
  compileAndExecute(compileData, debugData) {
332
- const { data, filename, fullPath, helpers, ɵɵstart, ɵɵcacheHit } = compileData;
436
+ const { dataOrHelpers, filename, fullPath, ɵɵstart, ɵɵcacheHit } = compileData;
333
437
  try {
334
- const templateFn = this.readFileAndGetCompiledFn(fullPath, data, helpers, filename, debugData);
335
- const immutableData = structuredClone(data);
336
- const html = templateFn.call(this, immutableData, helpers, ɵɵstart, ɵɵcacheHit);
438
+ const templateFn = this.readFileAndGetCompiledFn(fullPath, dataOrHelpers, filename, debugData);
439
+ const { data, helpers } = (0, utils_1.cloneData)(dataOrHelpers);
440
+ const html = templateFn.call(this, data, helpers, ɵɵstart, ɵɵcacheHit);
337
441
  return html;
338
442
  }
339
443
  catch (error) {
@@ -345,22 +449,21 @@ class Tao {
345
449
  }
346
450
  }
347
451
  manageError(error, filename, debugData) {
348
- // this.compiledStore.remove(filename); => pourquoi ?
349
452
  error.filename = filename;
350
453
  const errorData = this.handleErrorMessage(error, debugData);
351
- console.error(new Error(`Error in ${filename}: ${errorData.message}`));
352
454
  const errorHTML = this.initErrorTemplate(errorData);
353
455
  errorData.errorHTML = errorHTML;
456
+ (0, error_utils_1.logger)('error', `Error in ${filename}: ${errorData.message} at line ${errorData.lineNumber}`);
354
457
  return errorData;
355
458
  }
356
459
  executeChildFunction(executeData, debugData) {
357
- const { data, filename, helpers, compiledContent } = executeData;
460
+ const { dataOrHelpers, filename, compiledContent } = executeData;
358
461
  try {
359
- const immutableData = structuredClone(data);
360
- const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(data, helpers, this.helpersStore, compiledContent);
462
+ const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(dataOrHelpers, this.helpersStore, compiledContent);
361
463
  debugData.compiledAnonymousFnContent = contentReplaced;
362
464
  const templateFn = (0, utils_1.compileChildToFunction)(contentReplaced);
363
- const html = templateFn.call(this, immutableData, helpers);
465
+ const { data, helpers } = (0, utils_1.cloneData)(dataOrHelpers);
466
+ const html = templateFn.call(this, data, helpers);
364
467
  return html;
365
468
  }
366
469
  catch (error) {
@@ -378,13 +481,13 @@ class Tao {
378
481
  return errorData;
379
482
  }
380
483
  executeFunction(executeData, debugData) {
381
- const { data, filename, helpers, ɵɵstart, compiledContent, ɵɵcacheHit } = executeData;
484
+ const { dataOrHelpers, filename, ɵɵstart, compiledContent, ɵɵcacheHit } = executeData;
382
485
  try {
383
- const immutableData = structuredClone(data);
384
- const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(data, helpers, this.helpersStore, compiledContent);
486
+ const { data, helpers } = (0, utils_1.cloneData)(dataOrHelpers);
487
+ const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(dataOrHelpers, this.helpersStore, compiledContent);
385
488
  debugData.compiledAnonymousFnContent = contentReplaced;
386
489
  const templateFn = (0, utils_1.compileToFunction)(contentReplaced);
387
- const html = templateFn.call(this, immutableData, helpers, ɵɵstart, ɵɵcacheHit);
490
+ const html = templateFn.call(this, data, helpers, ɵɵstart, ɵɵcacheHit);
388
491
  return html;
389
492
  }
390
493
  catch (error) {
@@ -396,7 +499,6 @@ class Tao {
396
499
  }
397
500
  }
398
501
  handleErrorMessage(error, debugData) {
399
- var _a;
400
502
  const [finalMessage, fileContentPerLine, correctedLineNumber] = (0, error_utils_1.findOriginalLineNumberWithMessage)(error, debugData.compiledAnonymousFnContent, debugData.fileContent);
401
503
  const errorData = {
402
504
  filename: error.filename,
@@ -404,7 +506,7 @@ class Tao {
404
506
  message: finalMessage,
405
507
  lineNumber: correctedLineNumber,
406
508
  // Execution error is the last possible error
407
- type: (_a = error.type) !== null && _a !== void 0 ? _a : 'Execution Error',
509
+ type: error.type ?? 'Execution Error',
408
510
  isAChildError: false,
409
511
  errorHTML: '',
410
512
  };
@@ -413,38 +515,38 @@ class Tao {
413
515
  initErrorTemplate(errorData) {
414
516
  if (!this.config.development)
415
517
  return '';
416
- const templatesPath = node_path_1.default.join(__dirname, 'error');
518
+ const templatesPath = node_path_1.default.join(__dirname);
417
519
  const tao = new Tao({ views: templatesPath });
418
520
  return tao.render('error', errorData);
419
521
  }
420
- compileChildAndCache(content, filename, debugData) {
421
- const compiledContent = this.compileChild(content, debugData);
522
+ compileChildAndCache(content, filename) {
523
+ const compiledContent = this.compileChild(content);
422
524
  if (this.config.cache) {
423
525
  this.compiledStore.set(filename, compiledContent);
424
526
  }
425
527
  return compiledContent;
426
528
  }
427
- compileAndCache(content, filename, debugData) {
428
- const compiledContent = this.compile(content, filename, debugData);
529
+ compileAndCache(content, filename) {
530
+ const compiledContent = this.compile(content, filename);
429
531
  if (this.config.cache) {
430
532
  this.compiledStore.set(filename, compiledContent);
431
533
  }
432
534
  return compiledContent;
433
535
  }
434
- readChildFileAndGetCompiledFn(resolvedPath, data, helpers, filename, debugData) {
536
+ readChildFileAndGetCompiledFn(resolvedPath, dataOrHelpers, filename, debugData) {
435
537
  const content = this.readFile(resolvedPath);
436
538
  debugData.fileContent = content;
437
- const compiledContent = this.compileChildAndCache(content, filename, debugData);
438
- const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(data, helpers, this.helpersStore, compiledContent);
539
+ const compiledContent = this.compileChildAndCache(content, filename);
540
+ const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(dataOrHelpers, this.helpersStore, compiledContent);
439
541
  debugData.compiledAnonymousFnContent = contentReplaced;
440
542
  const templateFn = (0, utils_1.compileChildToFunction)(contentReplaced);
441
543
  return templateFn;
442
544
  }
443
- readFileAndGetCompiledFn(resolvedPath, data, helpers, filename, debugData) {
545
+ readFileAndGetCompiledFn(resolvedPath, dataOrHelpers, filename, debugData) {
444
546
  const content = this.readFile(resolvedPath);
445
547
  debugData.fileContent = content;
446
- const compiledContent = this.compileAndCache(content, filename, debugData);
447
- const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(data, helpers, this.helpersStore, compiledContent);
548
+ const compiledContent = this.compileAndCache(content, filename);
549
+ const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(dataOrHelpers, this.helpersStore, compiledContent);
448
550
  debugData.compiledAnonymousFnContent = contentReplaced;
449
551
  const templateFn = (0, utils_1.compileToFunction)(contentReplaced);
450
552
  return templateFn;
@@ -468,12 +570,12 @@ class Tao {
468
570
  * Handle dynamically defined templates
469
571
  */
470
572
  handleLoadedTemplate(templateData, debugData) {
471
- const { data, filename, helpers, ɵɵstart, ɵɵcacheHit } = templateData;
573
+ const { dataOrHelpers, filename, ɵɵstart, ɵɵcacheHit } = templateData;
472
574
  try {
575
+ const { data, helpers } = (0, utils_1.cloneData)(dataOrHelpers);
473
576
  const contentReplaced = this.compileLoadedTemplate(templateData, debugData);
474
577
  const templateFn = (0, utils_1.compileToFunction)(contentReplaced);
475
- const immutableData = structuredClone(data);
476
- const html = templateFn.call(this, immutableData, helpers, ɵɵstart, ɵɵcacheHit);
578
+ const html = templateFn.call(this, data, helpers, ɵɵstart, ɵɵcacheHit);
477
579
  return html;
478
580
  }
479
581
  catch (error) {
@@ -485,12 +587,12 @@ class Tao {
485
587
  }
486
588
  }
487
589
  handleLoadedChildTemplate(templateData, debugData) {
488
- const { data, filename, helpers } = templateData;
590
+ const { dataOrHelpers, filename } = templateData;
489
591
  try {
490
592
  const contentReplaced = this.compileLoadedChildTemplate(templateData, debugData);
491
593
  const templateFn = (0, utils_1.compileChildToFunction)(contentReplaced);
492
- const immutableData = structuredClone(data);
493
- const html = templateFn.call(this, immutableData, helpers);
594
+ const { data, helpers } = (0, utils_1.cloneData)(dataOrHelpers);
595
+ const html = templateFn.call(this, data, helpers);
494
596
  return html;
495
597
  }
496
598
  catch (error) {
@@ -502,16 +604,16 @@ class Tao {
502
604
  * Handle dynamically defined templates
503
605
  */
504
606
  compileLoadedTemplate(templateData, debugData) {
505
- const { data, filename, helpers, templateLoaded: content } = templateData;
506
- const compiledContent = this.compileAndCache(content, filename, debugData);
507
- const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(data, helpers, this.helpersStore, compiledContent);
607
+ const { dataOrHelpers, filename, templateLoaded: content } = templateData;
608
+ const compiledContent = this.compileAndCache(content, filename);
609
+ const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(dataOrHelpers, this.helpersStore, compiledContent);
508
610
  debugData.compiledAnonymousFnContent = contentReplaced;
509
611
  return contentReplaced;
510
612
  }
511
613
  compileLoadedChildTemplate(templateData, debugData) {
512
- const { data, filename, helpers, templateLoaded: content } = templateData;
513
- const compiledContent = this.compileChildAndCache(content, filename, debugData);
514
- const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(data, helpers, this.helpersStore, compiledContent);
614
+ const { dataOrHelpers, filename, templateLoaded: content } = templateData;
615
+ const compiledContent = this.compileChildAndCache(content, filename);
616
+ const contentReplaced = (0, utils_1.injectDataAndHelpersInTemplate)(dataOrHelpers, this.helpersStore, compiledContent);
515
617
  debugData.compiledAnonymousFnContent = contentReplaced;
516
618
  return contentReplaced;
517
619
  }
@@ -537,11 +639,11 @@ class Tao {
537
639
  */
538
640
  loadTemplate(name, template) {
539
641
  const duplicate = this.dynamictemplatesStore.get(name);
540
- if (!(0, checks_1.isTemplateDynamicallyDefined)(name)) {
642
+ if (!(0, validations_1.isTemplateDynamicallyDefined)(name)) {
541
643
  throw new Error(`Dynamically loaded template ${name} should start with a '@'`);
542
644
  }
543
645
  if (duplicate) {
544
- console.warn(`⚠️ Duplicate template name ${name} provided. Template content has been erased.`);
646
+ (0, error_utils_1.logger)('warn', `Duplicate template name ${name} provided. Template content has been erased.`);
545
647
  }
546
648
  this.dynamictemplatesStore.set(name, template);
547
649
  }