@itrocks/template 0.0.25 → 0.0.27

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/README.md CHANGED
@@ -377,13 +377,27 @@ Result:
377
377
 
378
378
  ### Including Another Template
379
379
 
380
- Any expression starting with `./` or `../` is considered a template include:
380
+ Any expression starting with `/`, `./` or `../` is considered a template include:
381
381
  ```html
382
382
  <div>
383
383
  {./another-template.html}
384
384
  </div>
385
385
  ```
386
386
 
387
+ The default contextual data is the one in the current scope.
388
+
389
+ You can pass parent or sub-data to your included template as an alternative context:
390
+ ```html
391
+ <div>
392
+ <!--subData-->
393
+ {./another-template.html-}
394
+ {./another-template.html(-)}
395
+ <!--end-->
396
+ {./another-template.html(subData)}
397
+ </div>
398
+ ```
399
+ In this example, `-` refers to the parent block context. Parentheses are optional in this specific case.
400
+
387
401
  #### Delimiting Rendered Content in an Included Template
388
402
 
389
403
  To keep templates W3C-compliant and browser-viewable, each HTML template may contain full HTML structure.
package/cjs/template.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { SortedArray } from '@itrocks/sorted-array';
2
- type BlockStack = {
2
+ type BlockStackEntry = {
3
3
  blockStart: number;
4
4
  collection: any[];
5
+ condition?: boolean;
5
6
  data: any;
6
7
  iteration: number;
7
8
  iterations: number;
8
- }[];
9
+ };
9
10
  export type VariableParser = [parser: string, (variable: string, data: any) => any];
10
11
  export declare const frontScripts: SortedArray<string>;
11
12
  export { Template };
@@ -13,7 +14,7 @@ export default class Template {
13
14
  data?: any;
14
15
  containerData?: any;
15
16
  blockBack: number;
16
- blockStack: BlockStack;
17
+ blockStack: BlockStackEntry[];
17
18
  doExpression: boolean;
18
19
  index: number;
19
20
  length: number;
package/cjs/template.js CHANGED
@@ -16,7 +16,7 @@ class Template {
16
16
  containerData;
17
17
  // block stack
18
18
  blockBack = 0;
19
- blockStack;
19
+ blockStack = [];
20
20
  // parser
21
21
  doExpression = true;
22
22
  index = 0;
@@ -65,7 +65,6 @@ class Template {
65
65
  this.addLinks.distinct = true;
66
66
  this.doneLinks.distinct = true;
67
67
  this.headLinks.distinct = true;
68
- this.blockStack = [];
69
68
  if (containerData) {
70
69
  this.blockStack.push({ blockStart: 0, collection: [], data: containerData, iteration: 0, iterations: 1 });
71
70
  }
@@ -177,7 +176,11 @@ class Template {
177
176
  }
178
177
  this.headLinks.push(...template.headLinks);
179
178
  this.headTitle = template.headTitle;
180
- return parsed.substring(parsed.indexOf('<!--BEGIN-->') + 12, parsed.indexOf('<!--END-->'));
179
+ const beginPosition = parsed.indexOf('<!--BEGIN-->');
180
+ const endPosition = parsed.indexOf('<!--END-->');
181
+ return (beginPosition > -1)
182
+ ? parsed.slice(beginPosition + 12, (endPosition > -1) ? endPosition : parsed.length)
183
+ : parsed;
181
184
  }
182
185
  isContextClean() {
183
186
  const clean = this.getCleanContext();
@@ -301,7 +304,7 @@ class Template {
301
304
  if (conditional && !parsed) {
302
305
  if ((typeof this.target)[0] === 's') {
303
306
  this.target = this.target.substring(0, this.target.lastIndexOf(' '));
304
- while ((this.index < this.length) && !' \n\r\t\f'.includes(this.source[this.index])) {
307
+ while ((this.index < this.length) && !' >\n\r\t\f'.includes(this.source[this.index])) {
305
308
  this.index++;
306
309
  this.start++;
307
310
  }
@@ -344,7 +347,23 @@ class Template {
344
347
  if (expression === '') {
345
348
  return undefined;
346
349
  }
347
- if ((expression[0] === '.') && (expression.startsWith('./') || expression.startsWith('../'))) {
350
+ if (((expression[0] === '.') && ((expression[1] === '/') || ((expression[1] === '.') && (expression[2] === '/'))))
351
+ || (expression[0] === '/')) {
352
+ let expressionEnd = expression.length - 1;
353
+ if (expression[expressionEnd] === '-') {
354
+ let blockBack = 1;
355
+ expressionEnd--;
356
+ while (expression[expressionEnd] === '-') {
357
+ blockBack++;
358
+ expressionEnd--;
359
+ }
360
+ const blockStack = this.blockStack;
361
+ return this.include(expression.slice(0, expressionEnd), blockStack[blockStack.length - blockBack].data);
362
+ }
363
+ if (expression[expressionEnd] === ')') {
364
+ const openPosition = expression.lastIndexOf('(');
365
+ return this.include(expression.slice(0, openPosition), await this.parsePath(expression.slice(openPosition + 1, expression.length - 1), data));
366
+ }
348
367
  return this.include(expression, data);
349
368
  }
350
369
  this.blockBack = 0;
@@ -355,7 +374,7 @@ class Template {
355
374
  }
356
375
  async parseVariable(variable, data) {
357
376
  if (variable === '') {
358
- return (typeof data === 'function')
377
+ return (((typeof data)[0] === 'f') && ((data + '')[0] !== 'c'))
359
378
  ? data.call()
360
379
  : data;
361
380
  }
@@ -371,8 +390,12 @@ class Template {
371
390
  return variable.substring(1, variable.length - 1);
372
391
  }
373
392
  if (firstChar === '-') {
374
- this.blockBack++;
375
- return this.blockStack[this.blockStack.length - this.blockBack].data;
393
+ let dataBack;
394
+ do {
395
+ this.blockBack++;
396
+ dataBack = this.blockStack[this.blockStack.length - this.blockBack];
397
+ } while (dataBack.condition);
398
+ return dataBack.data;
376
399
  }
377
400
  for (const [prefix, callback] of this.parsers) {
378
401
  if (firstChar === prefix) {
@@ -383,7 +406,7 @@ class Template {
383
406
  data = new rename_1.default(data);
384
407
  }
385
408
  let value = data[variable];
386
- return ((typeof value === 'function') && !value.prototype)
409
+ return (((typeof value)[0] === 'f') && ((value + '')[0] !== 'c'))
387
410
  ? value.call(data)
388
411
  : value;
389
412
  }
@@ -435,8 +458,7 @@ class Template {
435
458
  continue;
436
459
  }
437
460
  // end condition / loop block
438
- if ('eE'.includes(firstChar)
439
- && ['end-->', 'END-->'].includes(this.source.substring(this.index, this.index + 6))) {
461
+ if ((firstChar === 'e') && (this.source.substring(this.index, this.index + 6) === 'end-->')) {
440
462
  this.target += this.trimEndLine(this.source.substring(this.start, tagIndex));
441
463
  iteration++;
442
464
  if (iteration < iterations) {
@@ -457,7 +479,6 @@ class Template {
457
479
  continue;
458
480
  }
459
481
  // begin condition / loop block
460
- this.blockStack.push({ blockStart, collection, data, iteration, iterations });
461
482
  if (tagIndex > this.start) {
462
483
  this.target += this.trimEndLine(this.source.substring(this.start, tagIndex));
463
484
  this.start = tagIndex;
@@ -468,6 +489,7 @@ class Template {
468
489
  this.target = '';
469
490
  this.inLiteral = false;
470
491
  const condition = await this.parseExpression(data, '}', '-->');
492
+ this.blockStack.push({ blockStart, collection, condition, data, iteration, iterations });
471
493
  let blockData = condition ? (this.target ? data : undefined) : this.target;
472
494
  blockStart = this.index;
473
495
  iteration = 0;
package/esm/template.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { SortedArray } from '@itrocks/sorted-array';
2
- type BlockStack = {
2
+ type BlockStackEntry = {
3
3
  blockStart: number;
4
4
  collection: any[];
5
+ condition?: boolean;
5
6
  data: any;
6
7
  iteration: number;
7
8
  iterations: number;
8
- }[];
9
+ };
9
10
  export type VariableParser = [parser: string, (variable: string, data: any) => any];
10
11
  export declare const frontScripts: SortedArray<string>;
11
12
  export { Template };
@@ -13,7 +14,7 @@ export default class Template {
13
14
  data?: any;
14
15
  containerData?: any;
15
16
  blockBack: number;
16
- blockStack: BlockStack;
17
+ blockStack: BlockStackEntry[];
17
18
  doExpression: boolean;
18
19
  index: number;
19
20
  length: number;
package/esm/template.js CHANGED
@@ -11,7 +11,7 @@ export default class Template {
11
11
  containerData;
12
12
  // block stack
13
13
  blockBack = 0;
14
- blockStack;
14
+ blockStack = [];
15
15
  // parser
16
16
  doExpression = true;
17
17
  index = 0;
@@ -60,7 +60,6 @@ export default class Template {
60
60
  this.addLinks.distinct = true;
61
61
  this.doneLinks.distinct = true;
62
62
  this.headLinks.distinct = true;
63
- this.blockStack = [];
64
63
  if (containerData) {
65
64
  this.blockStack.push({ blockStart: 0, collection: [], data: containerData, iteration: 0, iterations: 1 });
66
65
  }
@@ -172,7 +171,11 @@ export default class Template {
172
171
  }
173
172
  this.headLinks.push(...template.headLinks);
174
173
  this.headTitle = template.headTitle;
175
- return parsed.substring(parsed.indexOf('<!--BEGIN-->') + 12, parsed.indexOf('<!--END-->'));
174
+ const beginPosition = parsed.indexOf('<!--BEGIN-->');
175
+ const endPosition = parsed.indexOf('<!--END-->');
176
+ return (beginPosition > -1)
177
+ ? parsed.slice(beginPosition + 12, (endPosition > -1) ? endPosition : parsed.length)
178
+ : parsed;
176
179
  }
177
180
  isContextClean() {
178
181
  const clean = this.getCleanContext();
@@ -296,7 +299,7 @@ export default class Template {
296
299
  if (conditional && !parsed) {
297
300
  if ((typeof this.target)[0] === 's') {
298
301
  this.target = this.target.substring(0, this.target.lastIndexOf(' '));
299
- while ((this.index < this.length) && !' \n\r\t\f'.includes(this.source[this.index])) {
302
+ while ((this.index < this.length) && !' >\n\r\t\f'.includes(this.source[this.index])) {
300
303
  this.index++;
301
304
  this.start++;
302
305
  }
@@ -339,7 +342,23 @@ export default class Template {
339
342
  if (expression === '') {
340
343
  return undefined;
341
344
  }
342
- if ((expression[0] === '.') && (expression.startsWith('./') || expression.startsWith('../'))) {
345
+ if (((expression[0] === '.') && ((expression[1] === '/') || ((expression[1] === '.') && (expression[2] === '/'))))
346
+ || (expression[0] === '/')) {
347
+ let expressionEnd = expression.length - 1;
348
+ if (expression[expressionEnd] === '-') {
349
+ let blockBack = 1;
350
+ expressionEnd--;
351
+ while (expression[expressionEnd] === '-') {
352
+ blockBack++;
353
+ expressionEnd--;
354
+ }
355
+ const blockStack = this.blockStack;
356
+ return this.include(expression.slice(0, expressionEnd), blockStack[blockStack.length - blockBack].data);
357
+ }
358
+ if (expression[expressionEnd] === ')') {
359
+ const openPosition = expression.lastIndexOf('(');
360
+ return this.include(expression.slice(0, openPosition), await this.parsePath(expression.slice(openPosition + 1, expression.length - 1), data));
361
+ }
343
362
  return this.include(expression, data);
344
363
  }
345
364
  this.blockBack = 0;
@@ -350,7 +369,7 @@ export default class Template {
350
369
  }
351
370
  async parseVariable(variable, data) {
352
371
  if (variable === '') {
353
- return (typeof data === 'function')
372
+ return (((typeof data)[0] === 'f') && ((data + '')[0] !== 'c'))
354
373
  ? data.call()
355
374
  : data;
356
375
  }
@@ -366,8 +385,12 @@ export default class Template {
366
385
  return variable.substring(1, variable.length - 1);
367
386
  }
368
387
  if (firstChar === '-') {
369
- this.blockBack++;
370
- return this.blockStack[this.blockStack.length - this.blockBack].data;
388
+ let dataBack;
389
+ do {
390
+ this.blockBack++;
391
+ dataBack = this.blockStack[this.blockStack.length - this.blockBack];
392
+ } while (dataBack.condition);
393
+ return dataBack.data;
371
394
  }
372
395
  for (const [prefix, callback] of this.parsers) {
373
396
  if (firstChar === prefix) {
@@ -378,7 +401,7 @@ export default class Template {
378
401
  data = new Str(data);
379
402
  }
380
403
  let value = data[variable];
381
- return ((typeof value === 'function') && !value.prototype)
404
+ return (((typeof value)[0] === 'f') && ((value + '')[0] !== 'c'))
382
405
  ? value.call(data)
383
406
  : value;
384
407
  }
@@ -430,8 +453,7 @@ export default class Template {
430
453
  continue;
431
454
  }
432
455
  // end condition / loop block
433
- if ('eE'.includes(firstChar)
434
- && ['end-->', 'END-->'].includes(this.source.substring(this.index, this.index + 6))) {
456
+ if ((firstChar === 'e') && (this.source.substring(this.index, this.index + 6) === 'end-->')) {
435
457
  this.target += this.trimEndLine(this.source.substring(this.start, tagIndex));
436
458
  iteration++;
437
459
  if (iteration < iterations) {
@@ -452,7 +474,6 @@ export default class Template {
452
474
  continue;
453
475
  }
454
476
  // begin condition / loop block
455
- this.blockStack.push({ blockStart, collection, data, iteration, iterations });
456
477
  if (tagIndex > this.start) {
457
478
  this.target += this.trimEndLine(this.source.substring(this.start, tagIndex));
458
479
  this.start = tagIndex;
@@ -463,6 +484,7 @@ export default class Template {
463
484
  this.target = '';
464
485
  this.inLiteral = false;
465
486
  const condition = await this.parseExpression(data, '}', '-->');
487
+ this.blockStack.push({ blockStart, collection, condition, data, iteration, iterations });
466
488
  let blockData = condition ? (this.target ? data : undefined) : this.target;
467
489
  blockStart = this.index;
468
490
  iteration = 0;
package/package.json CHANGED
@@ -67,5 +67,5 @@
67
67
  "test": "jest"
68
68
  },
69
69
  "types": "./esm/template.d.ts",
70
- "version": "0.0.25"
70
+ "version": "0.0.27"
71
71
  }