@ui-doc/html-renderer 0.3.0 → 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.
Files changed (102) hide show
  1. package/README.md +586 -151
  2. package/dist/HtmlCurlyBraceLexer.d.ts +4 -1
  3. package/dist/HtmlRenderer.d.ts +5 -5
  4. package/dist/InlineReader.d.ts +3 -2
  5. package/dist/{types/lexer.d.ts → Lexer.types.d.ts} +8 -5
  6. package/dist/NodeParser.d.ts +3 -2
  7. package/dist/{types/parser.d.ts → Parser.types.d.ts} +8 -8
  8. package/dist/{types/base.d.ts → Primitive.types.d.ts} +1 -1
  9. package/dist/{types/reader.d.ts → Reader.types.d.ts} +9 -7
  10. package/dist/Renderer.types.d.ts +14 -0
  11. package/dist/TemplateLoader.d.ts +3 -2
  12. package/dist/{types/token.d.ts → Token.types.d.ts} +1 -1
  13. package/dist/assets/services/expand.d.ts +19 -0
  14. package/dist/assets/ui-doc.cjs +283 -9
  15. package/dist/assets/ui-doc.cjs.map +1 -1
  16. package/dist/assets/ui-doc.css +1169 -250
  17. package/dist/assets/ui-doc.css.map +1 -1
  18. package/dist/assets/ui-doc.min.css +9 -1
  19. package/dist/assets/ui-doc.min.js +1 -1
  20. package/dist/assets/ui-doc.mjs +283 -9
  21. package/dist/assets/ui-doc.mjs.map +1 -1
  22. package/dist/assets/utils/delay.d.ts +1 -0
  23. package/dist/assets/utils/dom.d.ts +31 -0
  24. package/dist/assets/utils/select.d.ts +12 -0
  25. package/dist/index.cjs +161 -126
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.ts +6 -1
  28. package/dist/index.mjs +160 -126
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/nodes/CommentNode.d.ts +2 -1
  31. package/dist/nodes/Node.d.ts +1 -1
  32. package/dist/nodes/TemplateNode.d.ts +2 -1
  33. package/dist/nodes/index.d.ts +4 -2
  34. package/dist/nodes/tags/debug.d.ts +2 -1
  35. package/dist/nodes/tags/for.d.ts +4 -3
  36. package/dist/nodes/tags/if.d.ts +5 -4
  37. package/dist/nodes/tags/index.d.ts +1 -1
  38. package/dist/nodes/tags/page.d.ts +2 -1
  39. package/dist/nodes/tags/partial.d.ts +2 -1
  40. package/dist/nodes/tags/var.d.ts +2 -1
  41. package/dist/utils/index.d.ts +1 -1
  42. package/package.json +32 -29
  43. package/scripts/app.ts +5 -3
  44. package/scripts/{src → services}/example.ts +3 -3
  45. package/scripts/services/expand.ts +214 -0
  46. package/scripts/{src → services}/sidebar.ts +4 -3
  47. package/scripts/utils/delay.ts +12 -0
  48. package/scripts/utils/dom.ts +77 -0
  49. package/scripts/utils/select.ts +46 -0
  50. package/styles/01_resets/initial.css +8 -3
  51. package/styles/01_resets/root/color.css +19 -0
  52. package/styles/01_resets/root/font.css +28 -0
  53. package/styles/01_resets/root/space.css +30 -0
  54. package/styles/01_resets/root/witdh.css +12 -0
  55. package/styles/01_resets/root.css +61 -23
  56. package/styles/01_resets/typography.css +105 -8
  57. package/styles/02_utils/background.css +14 -0
  58. package/styles/02_utils/control.css +41 -0
  59. package/styles/02_utils/margin.css +150 -0
  60. package/styles/02_utils/padding.css +134 -0
  61. package/styles/02_utils/width.css +39 -0
  62. package/styles/03_components/button.css +42 -0
  63. package/styles/03_components/colors.css +7 -19
  64. package/styles/03_components/container.css +16 -0
  65. package/styles/03_components/example-markup.css +1 -6
  66. package/styles/03_components/grid-auto.css +49 -0
  67. package/styles/03_components/icons.css +7 -19
  68. package/styles/03_components/navigation/burger-control.css +75 -0
  69. package/styles/03_components/{nav → navigation}/list.css +9 -11
  70. package/styles/03_components/navigation/main.css +102 -0
  71. package/styles/03_components/spaces.css +8 -7
  72. package/styles/04_layout/body.css +22 -0
  73. package/styles/04_layout/inline-code.css +6 -0
  74. package/styles/04_layout/page.css +73 -0
  75. package/styles/index.css +58 -17
  76. package/templates/layouts/default.html +4 -6
  77. package/templates/layouts/example.html +1 -1
  78. package/templates/pages/default.html +13 -13
  79. package/templates/pages/index.html +9 -3
  80. package/templates/partials/code.html +1 -1
  81. package/templates/partials/colors.html +2 -2
  82. package/templates/partials/content.html +1 -1
  83. package/templates/partials/icons.html +3 -3
  84. package/templates/partials/nav-main.html +19 -8
  85. package/templates/partials/section.html +1 -1
  86. package/templates/partials/spaces.html +2 -2
  87. package/LICENSE.md +0 -9
  88. package/dist/assets/src/utils.d.ts +0 -2
  89. package/dist/types/index.d.ts +0 -6
  90. package/dist/types/renderer.d.ts +0 -14
  91. package/scripts/src/utils.ts +0 -20
  92. package/styles/02_objects/background.css +0 -7
  93. package/styles/02_objects/control.css +0 -25
  94. package/styles/02_objects/margin.css +0 -44
  95. package/styles/02_objects/padding.css +0 -44
  96. package/styles/02_objects/text.css +0 -3
  97. package/styles/02_objects/width.css +0 -16
  98. package/styles/03_components/nav/main.css +0 -39
  99. package/styles/03_components/text-flow.css +0 -5
  100. package/styles/04_layouts/page.css +0 -70
  101. /package/dist/assets/{src → services}/example.d.ts +0 -0
  102. /package/dist/assets/{src → services}/sidebar.d.ts +0 -0
package/dist/index.mjs CHANGED
@@ -6,6 +6,10 @@ class HTMLRendererError extends Error {
6
6
  }
7
7
 
8
8
  class HTMLRendererSyntaxError extends SyntaxError {
9
+ code;
10
+ line;
11
+ column;
12
+ source;
9
13
  constructor({ message, code, column, line, source, }) {
10
14
  super(message);
11
15
  this.name = 'HTMLRendererSyntaxError';
@@ -27,19 +31,20 @@ class ParserError extends Error {
27
31
  class TagNodeError extends Error {
28
32
  constructor(message) {
29
33
  super(message);
30
- this.name = 'TagNodeSyntaxError';
34
+ this.name = 'TagNodeError';
31
35
  }
32
36
  }
33
37
 
34
38
  const IDENTIFIER_CHARS = {
35
- identifier: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.',
39
+ 'identifier': 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.',
36
40
  'tag-identifier': 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
37
41
  };
38
42
  class HtmlCurlyBraceLexer {
43
+ reader;
44
+ currentTokens = [];
45
+ tagConsuming = false;
46
+ tagIdentified = false;
39
47
  constructor(reader) {
40
- this.currentTokens = [];
41
- this.tagConsuming = false;
42
- this.tagIdentified = false;
43
48
  this.reader = reader;
44
49
  }
45
50
  debug() {
@@ -69,11 +74,11 @@ class HtmlCurlyBraceLexer {
69
74
  if (this.tagConsuming) {
70
75
  return this.progressTag();
71
76
  }
72
- const char = this.reader.peak();
73
- if (char === '{' && this.reader.peak(2) === '{{') {
77
+ const char = this.reader.peek();
78
+ if (char === '{' && this.reader.peek(2) === '{{') {
74
79
  return this.consumeTagOpen();
75
80
  }
76
- if (char === '<' && this.reader.peak(4) === '<!--') {
81
+ if (char === '<' && this.reader.peek(4) === '<!--') {
77
82
  return this.consumeComment();
78
83
  }
79
84
  return this.consumeTemplate();
@@ -104,7 +109,7 @@ class HtmlCurlyBraceLexer {
104
109
  this.reader.consume(4);
105
110
  let content = '';
106
111
  while (!this.reader.isEof()) {
107
- if (this.reader.peak(3) === '-->') {
112
+ if (this.reader.peek(3) === '-->') {
108
113
  this.reader.consume(3);
109
114
  break;
110
115
  }
@@ -118,11 +123,11 @@ class HtmlCurlyBraceLexer {
118
123
  consumeTemplate() {
119
124
  let content = '';
120
125
  while (!this.reader.isEof()) {
121
- const peek = this.reader.peak();
122
- if (peek === '{' && this.reader.peak(2) === '{{') {
126
+ const peek = this.reader.peek();
127
+ if (peek === '{' && this.reader.peek(2) === '{{') {
123
128
  break;
124
129
  }
125
- if (peek === '<' && this.reader.peak(4) === '<!--') {
130
+ if (peek === '<' && this.reader.peek(4) === '<!--') {
126
131
  break;
127
132
  }
128
133
  content += this.reader.consume();
@@ -133,12 +138,12 @@ class HtmlCurlyBraceLexer {
133
138
  };
134
139
  }
135
140
  progressTag() {
136
- const char = this.reader.peak();
141
+ const char = this.reader.peek();
137
142
  if (char === ' ' || char === '\n' || char === '\r' || char === '\t') {
138
143
  this.reader.consume();
139
144
  return this.progressTag();
140
145
  }
141
- if (char === '}' && this.reader.peak(2) === '}}') {
146
+ if (char === '}' && this.reader.peek(2) === '}}') {
142
147
  return this.consumeTagClose();
143
148
  }
144
149
  if (char === '/') {
@@ -151,25 +156,25 @@ class HtmlCurlyBraceLexer {
151
156
  if (char === ':') {
152
157
  return this.consumeTagSeparator();
153
158
  }
154
- if (char === '"' || char === "'") {
159
+ if (char === '"' || char === '\'') {
155
160
  return this.consumeString();
156
161
  }
157
- if (char === '1' ||
158
- char === '2' ||
159
- char === '3' ||
160
- char === '4' ||
161
- char === '5' ||
162
- char === '6' ||
163
- char === '7' ||
164
- char === '8' ||
165
- char === '9' ||
166
- char === '0') {
162
+ if (char === '1'
163
+ || char === '2'
164
+ || char === '3'
165
+ || char === '4'
166
+ || char === '5'
167
+ || char === '6'
168
+ || char === '7'
169
+ || char === '8'
170
+ || char === '9'
171
+ || char === '0') {
167
172
  return this.consumeNumber();
168
173
  }
169
- if (char === 't' && this.reader.peak(4) === 'true') {
174
+ if (char === 't' && this.reader.peek(4) === 'true') {
170
175
  return this.consumeBoolean(true);
171
176
  }
172
- if (char === 'f' && this.reader.peak(5) === 'false') {
177
+ if (char === 'f' && this.reader.peek(5) === 'false') {
173
178
  return this.consumeBoolean(false);
174
179
  }
175
180
  if (char === '=' || char === '!' || char === '<' || char === '>') {
@@ -201,18 +206,18 @@ class HtmlCurlyBraceLexer {
201
206
  consumeNumber() {
202
207
  let value = '';
203
208
  while (!this.reader.isEof()) {
204
- const char = this.reader.peak();
205
- if (char === '1' ||
206
- char === '2' ||
207
- char === '3' ||
208
- char === '4' ||
209
- char === '5' ||
210
- char === '6' ||
211
- char === '7' ||
212
- char === '8' ||
213
- char === '9' ||
214
- char === '0' ||
215
- char === '.') {
209
+ const char = this.reader.peek();
210
+ if (char === '1'
211
+ || char === '2'
212
+ || char === '3'
213
+ || char === '4'
214
+ || char === '5'
215
+ || char === '6'
216
+ || char === '7'
217
+ || char === '8'
218
+ || char === '9'
219
+ || char === '0'
220
+ || char === '.') {
216
221
  value += this.reader.consume();
217
222
  }
218
223
  else {
@@ -221,7 +226,7 @@ class HtmlCurlyBraceLexer {
221
226
  }
222
227
  return {
223
228
  type: 'number',
224
- value: parseFloat(value),
229
+ value: Number.parseFloat(value),
225
230
  };
226
231
  }
227
232
  consumeBoolean(value) {
@@ -234,7 +239,7 @@ class HtmlCurlyBraceLexer {
234
239
  consumeOperator() {
235
240
  let operator = '';
236
241
  while (!this.reader.isEof()) {
237
- const char = this.reader.peak();
242
+ const char = this.reader.peek();
238
243
  if (char === '=' || char === '!' || char === '<' || char === '>') {
239
244
  operator += this.reader.consume();
240
245
  }
@@ -251,7 +256,7 @@ class HtmlCurlyBraceLexer {
251
256
  const chars = IDENTIFIER_CHARS[type];
252
257
  let name = '';
253
258
  while (!this.reader.isEof()) {
254
- const char = this.reader.peak();
259
+ const char = this.reader.peek();
255
260
  if (!chars.includes(char)) {
256
261
  break;
257
262
  }
@@ -265,14 +270,16 @@ class HtmlCurlyBraceLexer {
265
270
  }
266
271
 
267
272
  class InlineReader {
273
+ input;
274
+ source;
275
+ currentLine = 1;
276
+ currentPos = 1;
277
+ currentContent = '';
268
278
  constructor(input, source = 'inline') {
269
- this.currentLine = 1;
270
- this.currentPos = 1;
271
- this.currentContent = '';
272
279
  this.input = input;
273
280
  this.source = source;
274
281
  }
275
- peak(k = 1) {
282
+ peek(k = 1) {
276
283
  return this.input.slice(0, k);
277
284
  }
278
285
  consume(k = 1) {
@@ -305,16 +312,19 @@ class InlineReader {
305
312
  }
306
313
 
307
314
  function instanceofReader(object) {
308
- return (typeof object.peak === 'function' &&
309
- typeof object.consume === 'function' &&
310
- typeof object.isEof === 'function' &&
311
- typeof object.debug === 'function');
315
+ return (object !== null
316
+ && typeof object === 'object'
317
+ && typeof object.peek === 'function'
318
+ && typeof object.consume === 'function'
319
+ && typeof object.isEof === 'function'
320
+ && typeof object.debug === 'function');
312
321
  }
313
322
  class HtmlRenderer {
323
+ parser;
324
+ layouts = {};
325
+ partials = {};
326
+ pages = {};
314
327
  constructor(parser) {
315
- this.layouts = {};
316
- this.partials = {};
317
- this.pages = {};
318
328
  this.parser = parser;
319
329
  }
320
330
  addLayout(name, layout) {
@@ -349,26 +359,26 @@ class HtmlRenderer {
349
359
  }
350
360
  }
351
361
  generate(context, layout) {
352
- layout = layout !== null && layout !== void 0 ? layout : 'default';
353
- const content = this.layouts[layout] || undefined;
354
- if (!content) {
362
+ layout = layout ?? 'default';
363
+ const content = this.layouts[layout];
364
+ if (content === undefined) {
355
365
  throw new HTMLRendererError(`Layout "${layout}" not found. Please register it using "addLayout" method.`);
356
366
  }
357
367
  return this.render(content, this.generateContext(context));
358
368
  }
359
369
  page(name, context) {
360
- const content = this.pages[name] || this.pages.default || undefined;
361
- if (!content) {
370
+ const content = this.pages[name] ?? this.pages.default;
371
+ if (content === undefined) {
362
372
  throw new HTMLRendererError(`Page "${name}" not found. Please register it using "addPage" method.`);
363
373
  }
364
374
  return this.render(content, context);
365
375
  }
366
376
  partial(name, context) {
367
- const content = this.partials[name] || this.partials.default || undefined;
368
- if (!content) {
377
+ const content = this.partials[name] ?? this.partials.default;
378
+ if (content === undefined) {
369
379
  throw new HTMLRendererError(`Partial "${name}" not found. Please register it using "addPartial" method.`);
370
380
  }
371
- return this.render(content, context !== null && context !== void 0 ? context : {});
381
+ return this.render(content, context ?? {});
372
382
  }
373
383
  render(rootNode, context) {
374
384
  return rootNode.render(context, this);
@@ -392,8 +402,9 @@ class HtmlRenderer {
392
402
 
393
403
  const nodeOperators = ['==', '!=', '===', '!==', '<', '<=', '>', '>='];
394
404
  class Node {
405
+ type;
406
+ childNodes = [];
395
407
  constructor(type) {
396
- this.childNodes = [];
397
408
  this.type = type;
398
409
  }
399
410
  append(node) {
@@ -411,11 +422,12 @@ class Node {
411
422
  }
412
423
 
413
424
  class CommentNode extends Node {
425
+ content;
414
426
  constructor(content) {
415
427
  super('comment');
416
428
  this.content = content;
417
429
  }
418
- render() {
430
+ render(_context, _renderer) {
419
431
  return `<!-- ${this.content} -->`;
420
432
  }
421
433
  }
@@ -428,15 +440,16 @@ function readNestedValue(name, target) {
428
440
  if (name === '') {
429
441
  return target;
430
442
  }
443
+ const obj = target;
431
444
  if (index <= 0) {
432
- return target[name];
445
+ return obj[name];
433
446
  }
434
447
  const currentName = name.substring(0, index);
435
448
  const nextName = name.substring(index + 1);
436
- if (!target[currentName]) {
449
+ if (obj[currentName] === undefined || obj[currentName] === null) {
437
450
  return undefined;
438
451
  }
439
- return readNestedValue(nextName, target[currentName]);
452
+ return readNestedValue(nextName, obj[currentName]);
440
453
  }
441
454
  function escapeHtml(unsafe) {
442
455
  return unsafe
@@ -444,20 +457,21 @@ function escapeHtml(unsafe) {
444
457
  .replaceAll('<', '&lt;')
445
458
  .replaceAll('>', '&gt;')
446
459
  .replaceAll('"', '&quot;')
447
- .replaceAll("'", '&#039;');
460
+ .replaceAll('\'', '&#039;');
448
461
  }
449
462
 
450
463
  class TagNode extends Node {
451
464
  }
452
465
 
453
466
  class TagDebugNode extends TagNode {
467
+ contextKey;
454
468
  constructor({ contextKey }) {
455
469
  super('tag-debug');
456
- this.contextKey = contextKey !== null && contextKey !== void 0 ? contextKey : 'this';
470
+ this.contextKey = contextKey ?? 'this';
457
471
  }
458
472
  render(context) {
459
473
  const debugContext = this.contextKey !== 'this' ? readNestedValue(this.contextKey, context) : context;
460
- const debugContent = debugContext
474
+ const debugContent = debugContext !== undefined && debugContext !== null
461
475
  ? JSON.stringify(debugContext, null, 2)
462
476
  : `Current context for "${this.contextKey}" is empty`;
463
477
  return `<pre>${debugContent}</pre>`;
@@ -493,16 +507,17 @@ const parseTagDebugNode = {
493
507
  };
494
508
 
495
509
  class TagForNode extends TagNode {
510
+ contextKey;
496
511
  constructor({ contextKey }) {
497
512
  super('tag-for');
498
- this.contextKey = contextKey !== null && contextKey !== void 0 ? contextKey : 'this';
513
+ this.contextKey = contextKey ?? 'this';
499
514
  }
500
515
  render(context, renderer) {
501
516
  const contextNew = this.contextKey === 'this' ? context : readNestedValue(this.contextKey, context);
502
517
  if (Array.isArray(contextNew)) {
503
518
  return this.renderArray(contextNew, context, renderer);
504
519
  }
505
- if (typeof contextNew === 'object') {
520
+ if (contextNew !== null && typeof contextNew === 'object') {
506
521
  return this.renderObject(contextNew, context, renderer);
507
522
  }
508
523
  return '';
@@ -511,7 +526,7 @@ class TagForNode extends TagNode {
511
526
  return context
512
527
  .map((item, index) => {
513
528
  return this.renderChildNodes({
514
- ...(typeof item === 'object' ? item : {}),
529
+ ...(item !== null && typeof item === 'object' ? item : {}),
515
530
  _contextKey: this.contextKey,
516
531
  _loop: { index, value: item },
517
532
  _parent: parentContext,
@@ -522,10 +537,11 @@ class TagForNode extends TagNode {
522
537
  renderObject(context, parentContext, renderer) {
523
538
  return Object.keys(context)
524
539
  .map((key, index) => {
540
+ const value = context[key];
525
541
  return this.renderChildNodes({
526
- ...(typeof context[key] === 'object' ? context[key] : {}),
542
+ ...(value !== null && typeof value === 'object' ? value : {}),
527
543
  _contextKey: this.contextKey,
528
- _loop: { index, key, value: context[key] },
544
+ _loop: { index, key, value },
529
545
  _parent: parentContext,
530
546
  }, renderer);
531
547
  })
@@ -562,6 +578,7 @@ const parseTagForNode = {
562
578
  };
563
579
 
564
580
  class TagIfNode extends TagNode {
581
+ options;
565
582
  constructor(options) {
566
583
  super('tag-if');
567
584
  this.options = options;
@@ -571,7 +588,8 @@ class TagIfNode extends TagNode {
571
588
  if (this.options.operator) {
572
589
  value = this.compare(value, this.getValue(context, 'secondValue', 'secondContextKey'), this.options.operator);
573
590
  }
574
- return value ? this.renderChildNodes(context, renderer) : '';
591
+ const isTruthy = value !== undefined && value !== null && value !== false && value !== 0 && value !== '';
592
+ return isTruthy ? this.renderChildNodes(context, renderer) : '';
575
593
  }
576
594
  getValue(context, valueKey, contextKey) {
577
595
  return this.options[contextKey] !== undefined
@@ -657,9 +675,9 @@ const parseTagIfNode = {
657
675
  if (options.operator === undefined && options.firstContextKey === undefined) {
658
676
  throw new TagNodeError('Expected context key when no operator is given');
659
677
  }
660
- if (options.operator !== undefined &&
661
- options.secondContextKey === undefined &&
662
- options.secondValue === undefined) {
678
+ if (options.operator !== undefined
679
+ && options.secondContextKey === undefined
680
+ && options.secondValue === undefined) {
663
681
  throw new TagNodeError('Expected second context key or value when operator is given');
664
682
  }
665
683
  return new TagIfNode(options);
@@ -669,14 +687,18 @@ const parseTagIfNode = {
669
687
  };
670
688
 
671
689
  class TagPageNode extends TagNode {
690
+ name;
691
+ contextKey;
672
692
  constructor({ name, contextKey }) {
673
693
  super('tag-page');
674
- this.name = name !== null && name !== void 0 ? name : 'default';
675
- this.contextKey = contextKey !== null && contextKey !== void 0 ? contextKey : 'this';
694
+ this.name = name ?? 'default';
695
+ this.contextKey = contextKey ?? 'this';
676
696
  }
677
697
  render(context, renderer) {
678
698
  let pageName = this.name;
679
- const newContext = this.contextKey === 'this' ? context : readNestedValue(this.contextKey, context);
699
+ const newContext = this.contextKey === 'this'
700
+ ? context
701
+ : readNestedValue(this.contextKey, context);
680
702
  if (pageName.includes('.')) {
681
703
  const foundName = readNestedValue(pageName, context);
682
704
  if (typeof foundName === 'string' && foundName) {
@@ -705,10 +727,10 @@ const parseTagPageNode = {
705
727
  if (token.type !== 'identifier') {
706
728
  throw new TagNodeError('Expected tag identifier');
707
729
  }
708
- if (options.name && options.contextKey) {
730
+ if ((options.name !== undefined && options.name !== '') && (options.contextKey !== undefined && options.contextKey !== '')) {
709
731
  throw new TagNodeError('Expected only one name and context key');
710
732
  }
711
- if (options.name) {
733
+ if (options.name !== undefined && options.name !== '') {
712
734
  options.contextKey = token.name;
713
735
  }
714
736
  else {
@@ -723,13 +745,17 @@ const parseTagPageNode = {
723
745
  };
724
746
 
725
747
  class TagPartialNode extends TagNode {
748
+ name;
749
+ contextKey;
726
750
  constructor({ name, contextKey }) {
727
751
  super('tag-partial');
728
752
  this.name = name;
729
- this.contextKey = contextKey !== null && contextKey !== void 0 ? contextKey : 'this';
753
+ this.contextKey = contextKey ?? 'this';
730
754
  }
731
755
  render(context, renderer) {
732
- const newContext = this.contextKey === 'this' ? context : readNestedValue(this.contextKey, context);
756
+ const newContext = this.contextKey === 'this'
757
+ ? context
758
+ : readNestedValue(this.contextKey, context);
733
759
  return renderer.partial(this.name, newContext);
734
760
  }
735
761
  }
@@ -752,10 +778,10 @@ const parseTagPartialNode = {
752
778
  if (token.type !== 'identifier') {
753
779
  throw new TagNodeError('Expected tag identifier');
754
780
  }
755
- if (options.name && options.contextKey) {
781
+ if ((options.name !== undefined && options.name !== '') && (options.contextKey !== undefined && options.contextKey !== '')) {
756
782
  throw new TagNodeError('Expected only one name and context key');
757
783
  }
758
- if (options.name) {
784
+ if (options.name !== undefined && options.name !== '') {
759
785
  options.contextKey = token.name;
760
786
  }
761
787
  else {
@@ -763,7 +789,7 @@ const parseTagPartialNode = {
763
789
  }
764
790
  },
765
791
  create() {
766
- if (!options.name) {
792
+ if (options.name === undefined || options.name === '') {
767
793
  throw new TagNodeError('Expected partial name');
768
794
  }
769
795
  return new TagPartialNode(options);
@@ -773,16 +799,16 @@ const parseTagPartialNode = {
773
799
  };
774
800
 
775
801
  class TagVarNode extends TagNode {
802
+ contextKey;
803
+ escape;
776
804
  constructor({ contextKey, escape }) {
777
805
  super('tag-var');
778
806
  this.contextKey = contextKey;
779
807
  this.escape = !!escape;
780
808
  }
781
809
  render(context) {
782
- let value = readNestedValue(this.contextKey, context) || '';
783
- if (typeof value !== 'string') {
784
- value = String(value);
785
- }
810
+ const rawValue = readNestedValue(this.contextKey, context);
811
+ const value = rawValue === undefined || rawValue === null ? '' : String(rawValue);
786
812
  return this.escape ? escapeHtml(value) : value;
787
813
  }
788
814
  }
@@ -818,7 +844,7 @@ const parseTagVarNode = {
818
844
  options.escape = true;
819
845
  },
820
846
  create() {
821
- if (!options.contextKey) {
847
+ if (options.contextKey === undefined || options.contextKey === '') {
822
848
  throw new TagNodeError('Expected context key');
823
849
  }
824
850
  return new TagVarNode(options);
@@ -837,19 +863,18 @@ const tagNodes = [
837
863
  ];
838
864
 
839
865
  class TemplateNode extends Node {
866
+ content;
840
867
  constructor(content) {
841
868
  super('template');
842
869
  this.content = content;
843
870
  }
844
- render() {
871
+ render(_context, _renderer) {
845
872
  return this.content;
846
873
  }
847
874
  }
848
875
 
849
876
  class NodeParser {
850
- constructor() {
851
- this.tags = {};
852
- }
877
+ tags = {};
853
878
  static init() {
854
879
  const parser = new NodeParser();
855
880
  tagNodes.forEach(tag => parser.registerTagParser(tag));
@@ -867,7 +892,6 @@ class NodeParser {
867
892
  return this.parseChildren(lexer, tree);
868
893
  }
869
894
  parseChildren(lexer, parent) {
870
- var _a;
871
895
  let token = lexer.consume();
872
896
  while (token) {
873
897
  switch (token.type) {
@@ -878,12 +902,20 @@ class NodeParser {
878
902
  parent.append(new CommentNode(token.content));
879
903
  break;
880
904
  case 'tag-open':
881
- if (((_a = lexer.peek()) === null || _a === void 0 ? void 0 : _a.type) === 'tag-end') {
905
+ if (lexer.peek()?.type === 'tag-end') {
882
906
  return parent;
883
907
  }
884
908
  parent.append(this.parseTag(lexer));
885
909
  break;
886
- default:
910
+ case 'string':
911
+ case 'number':
912
+ case 'boolean':
913
+ case 'tag-identifier':
914
+ case 'identifier':
915
+ case 'operator':
916
+ case 'tag-close':
917
+ case 'tag-end':
918
+ case 'tag-separator':
887
919
  throw new ParserError(`Unexpected token type "${token.type}"`);
888
920
  }
889
921
  token = lexer.consume();
@@ -891,13 +923,12 @@ class NodeParser {
891
923
  return parent;
892
924
  }
893
925
  parseTag(lexer) {
894
- var _a, _b, _c;
895
926
  const tagIdentifier = lexer.consume();
896
927
  if (!tagIdentifier || tagIdentifier.type !== 'tag-identifier') {
897
928
  throw new ParserError('Expected tag identifier');
898
929
  }
899
930
  const tagDefinition = this.tags[tagIdentifier.name];
900
- if (!tagDefinition) {
931
+ if (tagDefinition === undefined) {
901
932
  throw new ParserError(`Unknown tag "${tagIdentifier.name}"`);
902
933
  }
903
934
  const { addToken, create } = tagDefinition.parse();
@@ -912,7 +943,8 @@ class NodeParser {
912
943
  }
913
944
  catch (error) {
914
945
  if (error instanceof TagNodeError) {
915
- throw new ParserError(`Error parsing tag ${tagIdentifier.name} - ${error.message}\nShould be something like: ${tagDefinition.example}`);
946
+ throw new ParserError(`Error parsing tag ${tagIdentifier.name} - ${error.message}\n`
947
+ + `Should be something like: ${tagDefinition.example}`);
916
948
  }
917
949
  throw error;
918
950
  }
@@ -921,11 +953,11 @@ class NodeParser {
921
953
  }
922
954
  this.parseChildren(lexer, node);
923
955
  const closeTokens = lexer.consume(3);
924
- if (!closeTokens ||
925
- ((_a = closeTokens[0]) === null || _a === void 0 ? void 0 : _a.type) !== 'tag-end' ||
926
- ((_b = closeTokens[1]) === null || _b === void 0 ? void 0 : _b.type) !== 'tag-identifier' ||
927
- closeTokens[1].name !== tagIdentifier.name ||
928
- ((_c = closeTokens[2]) === null || _c === void 0 ? void 0 : _c.type) !== 'tag-close') {
956
+ if (closeTokens === undefined
957
+ || closeTokens[0]?.type !== 'tag-end'
958
+ || closeTokens[1]?.type !== 'tag-identifier'
959
+ || closeTokens[1].name !== tagIdentifier.name
960
+ || closeTokens[2]?.type !== 'tag-close') {
929
961
  throw new ParserError('Expected closing tag');
930
962
  }
931
963
  return node;
@@ -933,24 +965,26 @@ class NodeParser {
933
965
  }
934
966
 
935
967
  class TemplateLoader {
936
- static async load({ renderer, fileSystem, templateBasePath = '@ui-doc/html-renderer/templates', }) {
937
- const templatePath = await fileSystem.assetLoader().packagePath(templateBasePath);
938
- const layoutFinder = fileSystem.createFileFinder([`${templatePath}/layouts/*.html`]);
939
- const pageFinder = fileSystem.createFileFinder([`${templatePath}/pages/*.html`]);
940
- const partialFinder = fileSystem.createFileFinder([`${templatePath}/partials/*.html`]);
941
- const name = (file) => fileSystem.fileBasename(file);
942
- const content = async (file) => (await fileSystem.fileRead(file)).trim();
943
- await Promise.all([
944
- layoutFinder.search(async (file) => {
945
- renderer.addLayout(name(file), { content: await content(file), source: file });
946
- }),
947
- pageFinder.search(async (file) => {
948
- renderer.addPage(name(file), { content: await content(file), source: file });
949
- }),
950
- partialFinder.search(async (file) => {
951
- renderer.addPartial(name(file), { content: await content(file), source: file });
952
- }),
953
- ]);
968
+ static TEMPLATES_PACKAGE = '@ui-doc/html-renderer/templates';
969
+ static async load({ renderer, fileSystem, templatePath, }) {
970
+ const paths = [
971
+ { folderName: 'layouts', addFunction: 'addLayout' },
972
+ { folderName: 'pages', addFunction: 'addPage' },
973
+ { folderName: 'partials', addFunction: 'addPartial' },
974
+ ];
975
+ await Promise.all(paths.map(async ({ folderName, addFunction }) => {
976
+ const searchPath = `${templatePath}/${folderName}`;
977
+ if (!(await fileSystem.isDirectory(searchPath))) {
978
+ return;
979
+ }
980
+ const finder = fileSystem.createFileFinder([`${searchPath}/*.html`]);
981
+ await finder.search(async (file) => {
982
+ renderer[addFunction](fileSystem.fileBasename(file), {
983
+ content: (await fileSystem.fileRead(file)).trim(),
984
+ source: file,
985
+ });
986
+ });
987
+ }));
954
988
  }
955
989
  }
956
990