/ lib / template.js
template.js
  1  import * as t from './builders.js';
  2  import {
  3    ReferenceTag,
  4    ArrayInitializerTag,
  5    OpenNodeTag,
  6    CloseNodeTag,
  7    DoctypeTag,
  8    EmbeddedNode,
  9    GapTag,
 10  } from './symbols.js';
 11  import * as btree from './btree.js';
 12  import { getOpenTag, get, isFragmentNode } from './tree.js';
 13  
 14  const { freeze } = Object;
 15  
 16  export const buildFilledGapFunction = (expressions) => (value) => {
 17    expressions.push(value);
 18    return t.buildGapTag();
 19  };
 20  
 21  export function* interpolateFragment(node, ref, expressions) {
 22    const open = getOpenTag(node);
 23  
 24    if (node.type !== null) throw new Error();
 25  
 26    const gap = buildFilledGapFunction(expressions);
 27  
 28    const counters = new Map();
 29  
 30    if (!open.value.type) {
 31      let currentRef = null;
 32      let isFragment = isFragmentNode(node);
 33      for (let tag of btree.traverse(node.children)) {
 34        switch (tag.type) {
 35          case DoctypeTag: {
 36            break;
 37          }
 38          case OpenNodeTag:
 39          case CloseNodeTag: {
 40            if (!isFragment) {
 41              yield tag;
 42            }
 43            break;
 44          }
 45  
 46          case ReferenceTag: {
 47            currentRef = tag;
 48            break;
 49          }
 50  
 51          case ArrayInitializerTag: {
 52            const { name } = currentRef.value;
 53            counters.set(name, -1);
 54            if (name === '.') {
 55              yield freeze({ ...ref });
 56            } else {
 57              yield currentRef;
 58            }
 59            yield tag;
 60            break;
 61          }
 62  
 63          case GapTag: {
 64            const { name, isArray, flags } = currentRef.value;
 65  
 66            if (name === '.') {
 67              // TODO check/combine flags
 68              yield freeze({ ...ref });
 69            } else {
 70              yield currentRef;
 71            }
 72  
 73            const count = counters.get(name) + 1;
 74  
 75            counters.set(name, count);
 76  
 77            const resolvedRef = t.buildReferenceTag(name, isArray, flags, count);
 78  
 79            yield gap(get(resolvedRef, node));
 80  
 81            break;
 82          }
 83  
 84          case EmbeddedNode: {
 85            const { name } = currentRef.value;
 86            if (name === '.') {
 87              yield freeze({ ...ref });
 88            } else {
 89              yield currentRef;
 90            }
 91            yield gap(tag.value);
 92            break;
 93          }
 94  
 95          default: {
 96            yield tag;
 97            break;
 98          }
 99        }
100      }
101    } else if (open.type === OpenNodeTag) {
102      yield freeze({ ...ref });
103      yield gap(get(ref, node));
104    } else {
105      throw new Error();
106    }
107  }