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 }