All files / lib class-string-parser.js

100% Statements 63/63
88.89% Branches 16/18
100% Functions 7/7
100% Lines 61/61
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 1001x     32x       17x       11x 11x 11x 11x 11x 11x       13x 13x 13x 13x 13x       43x 21x 21x 21x 21x 32x 32x 45x 15x 15x 15x 1x   15x 15x 15x 15x 15x 15x     15x 15x 15x 15x 15x   15x 24x 24x 24x     24x   24x 24x 24x   24x   24x     15x 15x   15x         15x   15x   15x 3x   17x 6x 6x   11x 11x 4x       21x    
import { builders } from 'glimmer-engine/dist/node_modules/glimmer-syntax';
 
function isLogicalIf(str) {
  return /(.+:.+:.+|.+:.+)/.test(str);
}
 
function isStatic(str) {
  return /:.+/.test(str);
}
 
function pushBound(value, column, nodes) {
  const columnEnd = column + value.length + 4; // {{}} = 4
  const node = builders.mustache(value);
  node.loc = builders.loc(1, column, 1, columnEnd);
  node.path.loc = builders.loc(1, column + 2, 1, columnEnd - 2);
  nodes.push(node);
  return columnEnd;
}
 
function pushText(value, column, nodes) {
  const columnEnd = column + value.length;
  const node = builders.text(value);
  node.loc = builders.loc(1, column, 1, columnEnd);
  nodes.push(node);
  return columnEnd;
}
 
export default function (classString, options) {
  const parts = (classString || '').split(/(\S+\s+)/).filter(s => s);
  let node;
  let column = 0;
  const nodes = [];
  parts.forEach((part) => {
    let trailingSpace = part.match(/\s+$/);
    trailingSpace = trailingSpace && trailingSpace[0];
    if (isLogicalIf(part)) {
      const [pathStr, ...values] = part.trim().split(':');
      const isUnless = values[0] === '';
      if (isUnless) {
        values.splice(0, 1); // remove leading blank that is not used in unless
      }
      const helperName = isUnless ? 'unless' : 'if';
      const startMust = column;
      column += 2; // "{{"
      const startIf = column;
      column += helperName.length;
      const endIf = column;
      // " " between {{if thing "then" "else"}}
      //                 ^
      column += 1; // " "
      const startPath = column;
      column += pathStr.length;
      const endPath = column;
      const path = builders.path(pathStr, builders.loc(1, startPath, 1, endPath));
 
      const params = values.map((value, i) => {
        const str = builders.string(value);
        const length = value.length;
        Eif (i < values.length) {
          // leading " " before {{if thing "then" "else"}}
          //                              ^      ^
          column += 1;
        }
        const startStr = column;
        column += length + 2; // plus 2 quotes
        const endStr = column;
 
        str.loc = builders.loc(1, startStr, 1, endStr);
 
        return str;
      });
 
      column += 2; // "}}"
      const endMust = column;
 
      node = builders.mustache(helperName, [
        path, ...params,
      ], null, null, builders.loc(1, startMust, 1, endMust));
 
      // "if" or "unless" location
      node.path.loc = builders.loc(1, startIf, 1, endIf);
 
      nodes.push(node);
 
      if (trailingSpace) {
        column = pushText(trailingSpace, column, nodes, options);
      }
    } else if (isStatic(part)) {
      const value = part.replace(/^:/, '');
      column = pushText(value, column, nodes, options);
    } else {
      column = pushBound(part.trim(), column, nodes, options);
      if (trailingSpace) {
        column = pushText(trailingSpace, column, nodes, options);
      }
    }
  });
  return nodes;
}