// TODO: pass third argument which is "original tokens" array

export function File(path, node) {
  this.print(path, 'program');
  node[this.key] = [
    ...this.beforeRef(node, 'program'),
    {reference: 'program'},
    ...this.afterRef(node, 'program')
  ];
}

export function Program(path, node) {
  // TODO: turn assignment on to t into a method,
  // automatically do reference assignment instead of relying on visitors
  const t = [];
  this.print(path, 'body', {
    before: (firstPath) => {
      t.push(...this.before(firstPath));
    },
    each: (path) => {
      t.push({reference: 'body#next'});
    },
    between: (leftPath, rightPath) => {
      t.push(...this.between(leftPath, rightPath));
    },
    after: (lastPath) => {
      t.push(...this.after(lastPath));
    }
  });
  node[this.key] = t;
}

export function Directive(path, node) {
  this.print(path, 'value');
  this.transformToLineTerminator(this.after('value'))
}

// export function DirectiveLiteral(path) {
//
// }

export function BlockStatement(path, node) {
  const t = [];

  // TODO: read formatting markers and omit newlines where applicable

  this.print(path, 'body', {
    before: (firstPath) => {
      const beforeElements = this.before(firstPath);
      // console.log(beforeElements)
      let beforeOpen = true;
      for (const element of (beforeElements: Array)) {
        if (beforeOpen) {
          // console.log(element);
          if (element.element === 'Punctuator' && element.value === '!') {
            t.push({element: 'Punctuator', value: '{'});
            beforeOpen = false;
          } else {
            t.push(element);
          }
        } else {
          t.push(element);
        }
      }
    },
    each: (path) => {
      t.push({reference: 'body#next'});
    },
    between: (leftPath, rightPath) => {
      t.push(...this.between(leftPath, rightPath));
    },
    after: (lastPath) => {
      const afterElements = this.after(lastPath);
      t.push(...afterElements);
      let beforeNewline = true;
      for (const element of (afterElements: Array)) {
        if (beforeNewline) {
          // console.log(element);
          if (element.element === 'LineTerminator' && element.value === '') {
            t.push({element: 'LineTerminator', value: '\n'});
            beforeNewline = false;
          } else {
            t.push(element);
          }
        } else {
          t.push(element);
        }
      }
      if (beforeNewline) {
        t.push({element: 'LineTerminator', value: '\n'});
      }
      t.push({element: 'Punctuator', value: '}'});
      t.push({element: 'LineTerminator', value: '\n'});
    }
  });
  node[this.key] = t;
}

@@ -1965,32 +1965,32 @@
     
-t.push(...afterElements)
+let beforeNewline = true
 ;%0A  
@@ -1995,39 +1995,42 @@
       let before
-Newline
+CloseCurly
  = true;%0A      f
@@ -2119,66 +2119,122 @@
     
-// console.log(element);%0A          if (element.
+if (element.element === 'LineTerminator') %7B%0A            if (element.value === '') %7B%0A              t.push(%7B
 element
- ===
+:
  'Li
@@ -2242,24 +2242,117 @@
 eTerminator'
+, value: '%5Cn'%7D);%0A              beforeNewline = false;%0A            %7D else if (beforeCloseCurly
  && element.
@@ -2354,37 +2354,72 @@
 ment.value === '
+%5Cn
 ') %7B%0A
+              t.push(element);%0A  
             t.pu
@@ -2428,34 +2428,30 @@
 (%7Belement: '
-LineTermin
+Punctu
 ator', value
@@ -2445,39 +2445,40 @@
 uator', value: '
-%5Cn
+%7D
 '%7D);%0A
+  
             befo
@@ -2479,32 +2479,101 @@
   before
-Newline = false;
+CloseCurly = false;%0A            %7D else %7B%0A              t.push(element);%0A            %7D
 %0A       
@@ -2776,24 +2776,56 @@
 %7D);%0A      %7D%0A
+      if (beforeCloseCurly) %7B%0A  
       t.push
@@ -2865,24 +2865,26 @@
 %7D'%7D);%0A      
+  
 t.push(%7Belem
@@ -2917,24 +2917,32 @@
 ue: '%5Cn'%7D);%0A
+      %7D%0A
     %7D%0A  %7D);%0A

tweak block printing