permissiveValue method

Node permissiveValue ({String untilTokensString, RegExp untilTokensRegExp })

Used for custom properties, at-rules, and variables (as fallback) Parses almost anything inside of {} [] () "" blocks until it reaches outer-most tokens.

First, it will try to parse comments and entities to reach the end. This is mostly like the Expression parser except no math is allowed.

Implementation

Node permissiveValue({String untilTokensString, RegExp untilTokensRegExp}) {
  final int index = parserInput.i;
  final List<Node> result = <Node>[];

  final TestChar tc = TestChar(untilTokensString, untilTokensRegExp);
  bool testCurrentChar() => tc.test(parserInput.currentChar());

  if (testCurrentChar()) return null;

  Node e;
  final List<Node> valueNodes = <Node>[];
  do {
    e = comment();
    if (e != null) {
      valueNodes.add(e);
      continue;
    }
    e = entity();
    if (e != null) valueNodes.add(e);
  } while (e != null);

  if (valueNodes.isNotEmpty) {
    final Expression expression = Expression(valueNodes);
    if (testCurrentChar()) {
      // done
      return expression;
    } else {
      result.add(expression);
    }
    // Preserve space before $parseUntil as it will not
    if (parserInput.prevChar() == ' ') {
      result.add(Anonymous(' ', index: index)); // fileInfo ?
    }
  }
  parserInput.save();

  List<ParseUntilReturnItem> value;
  try {
    value = parserInput.$parseUntil(
        tok: untilTokensString, tokre: untilTokensRegExp);
  } on ParserInputException catch (e) {
    if (e.expected != null) {
      parserInput.error("Expected '${e.expected}'", 'Parse');
    }
  }

  if (value != null) {
    if (value.length == 1 && value.single.isEnd) {
      parserInput.forget();
      return Anonymous('', index: index);
    }

    for (int i = 0; i < value.length; i++) {
      final ParseUntilReturnItem item = value[i];

      if (item.quote != null) {
        // Treat actual quotes as normal quoted values
        result.add(Quoted(item.quote, item.value,
            escaped: true, index: index, currentFileInfo: fileInfo));
      } else {
        if (i == value.length - 1) item.value = item.value.trim();

        // Treat like quoted values, but replace vars like unquoted expressions
        result.add(Quoted("'", item.value,
            escaped: true, index: index, currentFileInfo: fileInfo)
          ..variableRegex = RegExp(r'@([\w-]+)')
          ..propRegex = RegExp(r'\$([\w-]+)'));
      }
    }
    parserInput.forget();
    return Expression(result, noSpacing: true);
  }
  parserInput.restore();
  return null;

// 3.5.0.beta 20180627
//  permissiveValue: function (untilTokens) {
//      var i, e, done, value,
//          tok = untilTokens || ';',
//          index = parserInput.i, result = [];
//
//      function testCurrentChar() {
//          var char = parserInput.currentChar();
//          if (typeof tok === 'string') {
//              return char === tok;
//          } else {
//              return tok.test(char);
//          }
//      }
//      if (testCurrentChar()) {
//          return;
//      }
//      value = [];
//      do {
//          e = this.comment();
//          if (e) {
//              value.push(e);
//              continue;
//          }
//          e = this.entity();
//          if (e) {
//              value.push(e);
//          }
//      } while (e);
//
//      done = testCurrentChar();
//
//      if (value.length > 0) {
//          value = new(tree.Expression)(value);
//          if (done) {
//              return value;
//          }
//          else {
//              result.push(value);
//          }
//          // Preserve space before $parseUntil as it will not
//          if (parserInput.prevChar() === ' ') {
//              result.push(new tree.Anonymous(' ', index));
//          }
//      }
//      parserInput.save();
//
//      value = parserInput.$parseUntil(tok);
//
//      if (value) {
//          if (typeof value === 'string') {
//              error('Expected \'' + value + '\'', 'Parse');
//          }
//          if (value.length === 1 && value[0] === ' ') {
//              parserInput.forget();
//              return new tree.Anonymous('', index);
//          }
//          var item;
//          for (i = 0; i < value.length; i++) {
//              item = value[i];
//              if (Array.isArray(item)) {
//                  // Treat actual quotes as normal quoted values
//                  result.push(new tree.Quoted(item[0], item[1], true, index, fileInfo));
//              }
//              else {
//                  if (i === value.length - 1) {
//                      item = item.trim();
//                  }
//                  // Treat like quoted values, but replace vars like unquoted expressions
//                  var quote = new tree.Quoted('\'', item, true, index, fileInfo);
//                  quote.variableRegex = /@([\w-]+)/g;
//                  quote.propRegex = /\$([\w-]+)/g;
//                  result.push(quote);
//              }
//          }
//          parserInput.forget();
//          return new tree.Expression(result, true);
//      }
//      parserInput.restore();
//  },
}