lib/parser/grammar.js
function pathExpression (token, tokens) {
  const expression = []
  while (true) {
    if (!token) {
      break
    }
    if (token === ')') {
      tokens.unshift(token)
      break
    }
    if (includes('}]', token)) {
      throw new Error(`A fragment can't contain "${token}"`)
    }

    if (token === ',') {
      break
    }

    if (token === '[') {
      expression.push(escapedFragment(token, tokens))
    } else if (token === '(') {
      expression.push(pathExpressions(token, tokens))
    } else if (token === '{') {
      expression.push(customFragment(token, tokens))
    } else {
      expression.push(unescapedFragment(token, tokens))
    }
    token = tokens.shift()
  }
  return { _type: pathExpression.name, expression }
}
function pathExpression (token, tokens) {
  const expression = []
  while (true) {
    if (!token) {
      break
    }
    if (token === ')') {
      tokens.unshift(token)
      break
    }
    if (includes('}]', token)) {
      throw new Error(`A fragment can't contain "${token}"`)
    }

    if (token === ',') {
      break
    }

    if (token === '[') {
      expression.push(escapedFragment(token, tokens))
    } else if (token === '(') {
      expression.push(pathExpressions(token, tokens))
    } else if (token === '{') {
      expression.push(customFragment(token, tokens))
    } else {
      expression.push(unescapedFragment(token, tokens))
    }
    token = tokens.shift()
  }
  return { _type: pathExpression.name, expression }
}
function pathExpression ( token , tokens ) { const expression = [ ] while ( true ) { if ( ! token ) { break } if ( token === ')' ) { tokens . unshift ( token ) break } if ( includes ( '}]' , token ) ) { throw new Error ( ` ${ token } ` ) } if ( token === ',' ) { break } if ( token === '[' ) { expression . push ( escapedFragment ( token , tokens ) ) } else if ( token === '(' ) { expression . push ( pathExpressions ( token , tokens ) ) } else if ( token === '{' ) { expression . push ( customFragment ( token , tokens ) ) } else { expression . push ( unescapedFragment ( token , tokens ) ) } token = tokens . shift ( ) } return { _type : pathExpression . name , expression } }
ends with "," or with "end of string"
ends with or with end of string