Example #1
0
  void Inspect::operator()(Declaration* dec)
  {
    if (dec->value()->concrete_type() == Expression::NULL_VAL) return;
    bool was_decl = in_declaration;
    in_declaration = true;
    if (output_style() == NESTED)
      indentation += dec->tabs();
    append_indentation();
    dec->property()->perform(this);
    append_colon_separator();

    if (dec->value()->concrete_type() == Expression::SELECTOR) {
      Listize listize(*ctx);
      dec->value()->perform(&listize)->perform(this);
    } else {
      dec->value()->perform(this);
    }

    if (dec->is_important()) {
      append_optional_space();
      append_string("!important");
    }
    append_delimiter();
    if (output_style() == NESTED)
      indentation -= dec->tabs();
    in_declaration = was_decl;
  }
Example #2
0
  void Output::operator()(Media_Block* m)
  {
    if (m->is_invisible()) return;

    List*  q     = m->media_queries();
    Block* b     = m->block();

    // Filter out media blocks that aren't printable (process its children though)
    if (!Util::isPrintable(m, output_style())) {
      for (size_t i = 0, L = b->length(); i < L; ++i) {
        Statement* stm = (*b)[i];
        if (dynamic_cast<Has_Block*>(stm)) {
          stm->perform(this);
        }
      }
      return;
    }
    if (output_style() == NESTED) indentation += m->tabs();
    append_indentation();
    append_token("@media", m);
    append_mandatory_space();
    in_media_block = true;
    q->perform(this);
    in_media_block = false;
    append_scope_opener();

    for (size_t i = 0, L = b->length(); i < L; ++i) {
      if ((*b)[i]) (*b)[i]->perform(this);
      if (i < L - 1) append_special_linefeed();
    }

    if (output_style() == NESTED) indentation -= m->tabs();
    append_scope_closer();
  }
Example #3
0
  void Output::operator()(Supports_Block* f)
  {
    if (f->is_invisible()) return;

    Supports_Condition* c = f->condition();
    Block* b              = f->block();

    // Filter out feature blocks that aren't printable (process its children though)
    if (!Util::isPrintable(f, output_style())) {
      for (size_t i = 0, L = b->length(); i < L; ++i) {
        Statement* stm = (*b)[i];
        if (dynamic_cast<Has_Block*>(stm)) {
          stm->perform(this);
        }
      }
      return;
    }

    if (output_style() == NESTED) indentation += f->tabs();
    append_indentation();
    append_token("@supports", f);
    append_mandatory_space();
    c->perform(this);
    append_scope_opener();

    if (b->has_non_hoistable()) {
      // JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable
      append_scope_opener();

      for (size_t i = 0, L = b->length(); i < L; ++i) {
        Statement* stm = (*b)[i];
        if (!stm->is_hoistable()) {
          stm->perform(this);
        }
      }

      append_scope_closer();

      for (size_t i = 0, L = b->length(); i < L; ++i) {
        Statement* stm = (*b)[i];
        if (stm->is_hoistable()) {
          stm->perform(this);
        }
      }
    }
    else {
      // JMA - not hoisted, just output in order
      for (size_t i = 0, L = b->length(); i < L; ++i) {
        Statement* stm = (*b)[i];
        stm->perform(this);
        if (i < L - 1) append_special_linefeed();
      }
    }

    if (output_style() == NESTED) indentation -= f->tabs();

    append_scope_closer();

  }
Example #4
0
  void Inspect::operator()(Complex_Selector* c)
  {
    Compound_Selector*           head = c->head();
    Complex_Selector*            tail = c->tail();
    Complex_Selector::Combinator comb = c->combinator();

    if (c->has_line_feed()) {
      if (!(c->has_parent_ref())) {
        append_optional_linefeed();
        append_indentation();
      }
    }

    if (head && head->length() != 0) head->perform(this);
    bool is_empty = !head || head->length() == 0 || head->is_empty_reference();
    bool is_tail = head && !head->is_empty_reference() && tail;
    if (output_style() == COMPRESSED && comb != Complex_Selector::ANCESTOR_OF) scheduled_space = 0;

    switch (comb) {
      case Complex_Selector::ANCESTOR_OF:
        if (is_tail) append_mandatory_space();
      break;
      case Complex_Selector::PARENT_OF:
        append_optional_space();
        append_string(">");
        append_optional_space();
      break;
      case Complex_Selector::ADJACENT_TO:
        append_optional_space();
        append_string("+");
        append_optional_space();
      break;
      case Complex_Selector::REFERENCE:
        append_mandatory_space();
        append_string("/");
        c->reference()->perform(this);
        append_string("/");
        append_mandatory_space();
      break;
      case Complex_Selector::PRECEDES:
        if (is_empty) append_optional_space();
        else append_mandatory_space();
        append_string("~");
        if (tail) append_mandatory_space();
        else append_optional_space();
      break;
    }
    if (tail && comb != Complex_Selector::ANCESTOR_OF) {
      if (c->has_line_break()) append_optional_linefeed();
    }
    if (tail) tail->perform(this);
    if (!tail && c->has_line_break()) {
      if (output_style() == COMPACT) {
        append_mandatory_space();
      }
    }
  }
Example #5
0
 void Emitter::append_indentation()
 {
   if (output_style() == COMPRESSED) return;
   if (output_style() == COMPACT) return;
   if (in_declaration && in_comma_array) return;
   if (scheduled_linefeed && indentation)
     scheduled_linefeed = 1;
   std::string indent = "";
   for (size_t i = 0; i < indentation; i++)
     indent += ctx ? ctx->indent : "  ";
   append_string(indent);
 }
Example #6
0
 void Emitter::append_delimiter()
 {
   scheduled_delimiter = true;
   if (output_style() == COMPACT) {
     if (indentation == 0) {
       append_mandatory_linefeed();
     } else {
       append_mandatory_space();
     }
   } else if (output_style() != COMPRESSED) {
     append_optional_linefeed();
   }
 }
Example #7
0
  // statements
  void Inspect::operator()(Block* block)
  {
    if (!block->is_root()) {
      add_open_mapping(block);
      append_scope_opener();
    }
    if (output_style() == NESTED) indentation += block->tabs();
    for (size_t i = 0, L = block->length(); i < L; ++i) {
      (*block)[i]->perform(this);
    }
    if (output_style() == NESTED) indentation -= block->tabs();
    if (!block->is_root()) {
      append_scope_closer();
      add_close_mapping(block);
    }

  }
Example #8
0
 void Emitter::append_mandatory_linefeed()
 {
   if (output_style() != COMPRESSED) {
     scheduled_linefeed = 1;
     scheduled_space = 0;
     // flush_schedules();
   }
 }
Example #9
0
 void Emitter::append_special_linefeed()
 {
   if (output_style() == COMPACT) {
     append_mandatory_linefeed();
     for (size_t p = 0; p < indentation; p++)
       append_string(ctx ? ctx->indent : "  ");
   }
 }
Example #10
0
 void Emitter::append_optional_linefeed()
 {
   if (in_declaration && in_comma_array) return;
   if (output_style() == COMPACT) {
     append_mandatory_space();
   } else {
     append_mandatory_linefeed();
   }
 }
Example #11
0
 void Emitter::append_optional_space()
 {
   if (output_style() != COMPRESSED && buffer().size()) {
     char lst = buffer().at(buffer().length() - 1);
     if (!isspace(lst) || scheduled_delimiter) {
       append_mandatory_space();
     }
   }
 }
Example #12
0
 void Emitter::append_scope_closer(AST_Node* node)
 {
   -- indentation;
   scheduled_linefeed = 0;
   if (output_style() == COMPRESSED)
     scheduled_delimiter = false;
   if (output_style() == EXPANDED) {
     append_optional_linefeed();
     append_indentation();
   } else {
     append_optional_space();
   }
   append_string("}");
   if (node) add_close_mapping(node);
   append_optional_linefeed();
   if (indentation != 0) return;
   if (output_style() != COMPRESSED)
     scheduled_linefeed = 2;
 }
Example #13
0
 void Inspect::operator()(Compound_Selector* s)
 {
   for (size_t i = 0, L = s->length(); i < L; ++i) {
     (*s)[i]->perform(this);
   }
   if (s->has_line_break()) {
     if (output_style() != COMPACT) {
       append_optional_linefeed();
     }
   }
 }
Example #14
0
 void Output::operator()(String_Constant* s)
 {
   std::string value(s->value());
   if (s->can_compress_whitespace() && output_style() == COMPRESSED) {
     value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
   }
   if (!in_comment) {
     append_token(string_to_output(value), s);
   } else {
     append_token(value, s);
   }
 }
Example #15
0
  void Inspect::operator()(List* list)
  {
    std::string sep(list->separator() == SASS_SPACE ? " " : ",");
    if (output_style() != COMPRESSED && sep == ",") sep += " ";
    else if (in_media_block && sep != " ") sep += " "; // verified
    if (list->empty()) return;
    bool items_output = false;

    bool was_space_array = in_space_array;
    bool was_comma_array = in_comma_array;
    if (!in_declaration && (
        (list->separator() == SASS_SPACE && in_space_array) ||
        (list->separator() == SASS_COMMA && in_comma_array)
    )) {
      append_string("(");
    }

    if (list->separator() == SASS_SPACE) in_space_array = true;
    else if (list->separator() == SASS_COMMA) in_comma_array = true;

    for (size_t i = 0, L = list->size(); i < L; ++i) {
      Expression* list_item = (*list)[i];
      if (list_item->is_invisible()) {
        continue;
      }
      if (items_output) {
        append_string(sep);
      }
      if (items_output && sep != " ")
        append_optional_space();
      list_item->perform(this);
      items_output = true;
    }

    in_comma_array = was_comma_array;
    in_space_array = was_space_array;
    if (!in_declaration && (
        (list->separator() == SASS_SPACE && in_space_array) ||
        (list->separator() == SASS_COMMA && in_comma_array)
    )) {
      append_string(")");
    }

  }
Example #16
0
  OutputBuffer Output::get_buffer(void)
  {

    Emitter emitter(opt);
    Inspect inspect(emitter);

    size_t size_nodes = top_nodes.size();
    for (size_t i = 0; i < size_nodes; i++) {
      top_nodes[i]->perform(&inspect);
      inspect.append_mandatory_linefeed();
    }

    // flush scheduled outputs
    // maybe omit semicolon if possible
    inspect.finalize(wbuf.buffer.size() == 0);
    // prepend buffer on top
    prepend_output(inspect.output());
    // make sure we end with a linefeed
    if (!ends_with(wbuf.buffer, opt.linefeed)) {
      // if the output is not completely empty
      if (!wbuf.buffer.empty()) append_string(opt.linefeed);
    }

    // search for unicode char
    for(const char& chr : wbuf.buffer) {
      // skip all ascii chars
      // static cast to unsigned to handle `char` being signed / unsigned
      if (static_cast<unsigned>(chr) < 128) continue;
      // declare the charset
      if (output_style() != COMPRESSED)
        charset = "@charset \"UTF-8\";"
                + std::string(opt.linefeed);
      else charset = "\xEF\xBB\xBF";
      // abort search
      break;
    }

    // add charset as first line, before comments and imports
    if (!charset.empty()) prepend_string(charset);

    return wbuf;

  }
Example #17
0
  // append some text or token to the buffer
  void Emitter::append_string(const std::string& text)
  {
    // write space/lf
    flush_schedules();

    if (in_comment && output_style() == COMPACT) {
      // unescape comment nodes
      std::string out = comment_to_string(text);
      // add to buffer
      wbuf.buffer += out;
      // account for data in source-maps
      wbuf.smap.append(Offset(out));
    } else {
      // add to buffer
      wbuf.buffer += text;
      // account for data in source-maps
      wbuf.smap.append(Offset(text));
    }
  }
Example #18
0
  OutputBuffer Output::get_buffer(void)
  {

    Emitter emitter(ctx);
    Inspect inspect(emitter);

    size_t size_nodes = top_nodes.size();
    for (size_t i = 0; i < size_nodes; i++) {
      top_nodes[i]->perform(&inspect);
      inspect.append_mandatory_linefeed();
    }

    // flush scheduled outputs
    inspect.finalize();
    // prepend buffer on top
    prepend_output(inspect.output());
    // make sure we end with a linefeed
    if (!ends_with(wbuf.buffer, ctx->linefeed)) {
      // if the output is not completely empty
      if (!wbuf.buffer.empty()) append_string(ctx->linefeed);
    }

    // search for unicode char
    for(const char& chr : wbuf.buffer) {
      // skip all ascii chars
      if (chr >= 0) continue;
      // declare the charset
      if (output_style() != SASS_STYLE_COMPRESSED)
        charset = "@charset \"UTF-8\";"
                  + ctx->linefeed;
      else charset = "\xEF\xBB\xBF";
      // abort search
      break;
    }

    // add charset as first line, before comments and imports
    if (!charset.empty()) prepend_string(charset);

    return wbuf;

  }
Example #19
0
 void Output::operator()(Comment* c)
 {
   std::string txt = c->text()->to_string(opt);
   // if (indentation && txt == "/**/") return;
   bool important = c->is_important();
   if (output_style() != COMPRESSED || important) {
     if (buffer().size() == 0) {
       top_nodes.push_back(c);
     } else {
       in_comment = true;
       append_indentation();
       c->text()->perform(this);
       in_comment = false;
       if (indentation == 0) {
         append_mandatory_linefeed();
       } else {
         append_optional_linefeed();
       }
     }
   }
 }
Example #20
0
  void Output::operator()(Ruleset* r)
  {
    Selector* s     = r->selector();
    Block*    b     = r->block();
    bool      decls = false;

    // Filter out rulesets that aren't printable (process its children though)
    if (!Util::isPrintable(r, output_style())) {
      for (size_t i = 0, L = b->length(); i < L; ++i) {
        Statement* stm = (*b)[i];
        if (dynamic_cast<Has_Block*>(stm)) {
          stm->perform(this);
        }
      }
      return;
    }

    if (b->has_non_hoistable()) {
      decls = true;
      if (output_style() == NESTED) indentation += r->tabs();
      if (opt.source_comments) {
        std::stringstream ss;
        append_indentation();
        ss << "/* line " << r->pstate().line + 1 << ", " << r->pstate().path << " */";
        append_string(ss.str());
        append_optional_linefeed();
      }
      s->perform(this);
      append_scope_opener(b);
      for (size_t i = 0, L = b->length(); i < L; ++i) {
        Statement* stm = (*b)[i];
        bool bPrintExpression = true;
        // Check print conditions
        if (typeid(*stm) == typeid(Declaration)) {
          Declaration* dec = static_cast<Declaration*>(stm);
          if (dec->value()->concrete_type() == Expression::STRING) {
            String_Constant* valConst = static_cast<String_Constant*>(dec->value());
            std::string val(valConst->value());
            if (auto qstr = dynamic_cast<String_Quoted*>(valConst)) {
              if (!qstr->quote_mark() && val.empty()) {
                bPrintExpression = false;
              }
            }
          }
          else if (dec->value()->concrete_type() == Expression::LIST) {
            List* list = static_cast<List*>(dec->value());
            bool all_invisible = true;
            for (size_t list_i = 0, list_L = list->length(); list_i < list_L; ++list_i) {
              Expression* item = (*list)[list_i];
              if (!item->is_invisible()) all_invisible = false;
            }
            if (all_invisible) bPrintExpression = false;
          }
        }
        // Print if OK
        if (!stm->is_hoistable() && bPrintExpression) {
          stm->perform(this);
        }
      }
      if (output_style() == NESTED) indentation -= r->tabs();
      append_scope_closer(b);
    }

    if (b->has_hoistable()) {
      if (decls) ++indentation;
      for (size_t i = 0, L = b->length(); i < L; ++i) {
        Statement* stm = (*b)[i];
        if (stm->is_hoistable()) {
          stm->perform(this);
        }
      }
      if (decls) --indentation;
    }
  }