text: 'use strict';
  
  var gonzales = require('gonzales-pe');
  
  let option = {
    /**
     * Option's name as it's used in config.
     * @type {String}
     */
    get name() {
      return 'always-semicolon';
    },
  
    get runBefore() {
      return 'space-before-closing-brace';
    },
  
    /**
     * List of syntaxes that are supported by this option.
     * @type {Array}
     */
    get syntax() {
      return ['css', 'less', 'sass', 'scss'];
    },
  
    /**
     * Types of values this option accepts in config.
     * @type {Object}
     */
    get accepts() {
      return {
        boolean: [true]
      };
    },
  
    /**
     * Checks ast for code style errors.
     *
     * @param {Node} ast
     * @return {Array?} List of found errors.
     */
    lint(ast) {
      var errors = [];
  
      ast.traverseByType('block', block => {
        block.eachFor(currentNode => {
          var nodeWithoutSemicolon;
          // Skip nodes that already have `;` at the end:
          if (currentNode.is('declarationDelimiter')) return null;
  
          // Add semicolon only after declarations and includes.
          // If current node is include, insert semicolon right into it.
          // If it's declaration, look for value node:
          if (currentNode.is('include') || currentNode.is('extend')) {
            nodeWithoutSemicolon = currentNode;
          } else if (currentNode.is('declaration')) {
            nodeWithoutSemicolon = currentNode.last('value');
          } else {
            return;
          }
  
          errors.push({
            message: 'Missing semicolon',
            line: nodeWithoutSemicolon.end.line,
            column: nodeWithoutSemicolon.end.column + 1
          });
  
          // Stop looping through block's children:
          return null;
        });
      });
  
      return errors;
    },
  
    /**
     * Processes ast and fixes found code style errors.
     * @param {Node} ast
     */
    process(ast) {
      var nodeWithoutSemicolon;
  
      ast.traverseByType('block', block => {
        block.eachFor(currentNode => {
          // Skip nodes that already have `;` at the end:
          if (currentNode.is('declarationDelimiter')) return null;
  
          // Add semicolon only after declarations and includes.
          // If current node is include, insert semicolon right into it.
          // If it's declaration, look for value node:
          if (currentNode.is('include') || currentNode.is('extend')) {
            nodeWithoutSemicolon = currentNode;
          } else if (currentNode.is('declaration')) {
            nodeWithoutSemicolon = currentNode.last('value');
          } else {
            return;
          }
  
          // Check if there are spaces and comments at the end of the node
          for (var j = nodeWithoutSemicolon.length; j--;) {
            var lastNode = nodeWithoutSemicolon.get(j);
  
            // If the node's last child is block, do not add semicolon:
            // TODO: Add syntax check and run the code only for scss
            if (lastNode.is('block')) {
              return null;
            } else if (!lastNode.is('space') && !lastNode.is('multilineComment') && !lastNode.is('singlelineComment')) {
              j++;
              break;
            }
          }
  
          var declDelim = gonzales.createNode({
            type: 'declarationDelimiter',
            content: ';'
          });
          nodeWithoutSemicolon.insert(j, declDelim);
          return null;
        });
      });
    },
  
    /**
     * Detects the value of this option in ast.
     * @param {Node} ast
     * @return {Array?} List of detected values
     */
    detect(ast) {
      var detected = [];
  
      ast.traverseByType('block', block => {
        block.eachFor(node => {
          if (node.is('declarationDelimiter')) {
            detected.push(true);
            return null;
          } else if (node.is('declaration')) {
            detected.push(false);
            return null;
          }
        });
      });
  
      return detected;
    }
  };
  
  module.exports = option;