all files / remark-lint-sentence-newline/ index.js

100% Statements 40/40
100% Branches 22/22
100% Functions 3/3
100% Lines 40/40
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       13×       42× 42×       34× 102× 102× 66×   36× 33× 33×     34×     13× 13× 42×     42× 13×     29×     21× 11×     10× 10×     10×                            
var visit = require('unist-util-visit');
 
function sentenceNewline(ast, file, preferred, done) {
  var blacklist = [];
  if (typeof preferred === 'object' && !('length' in preferred)) {
    blacklist = preferred.blacklist;
  }
 
  visit(ast, 'text', function (node) {
    var sentenceStops = [
      '!', '.', '?'
    ];
 
    function getNextSentenceStop(value, startIndex) {
      var result = {index: -1, sentenceStop: ''};
      if (startIndex >= value.length) {
        return result;
      }
      // search for all sentence stop types
      // return the one with the lowest index
      for (var i = 0; i < sentenceStops.length; ++i) {
        var index = value.indexOf(sentenceStops[i], startIndex);
        if (index === -1) {
          continue;
        }
        if (result.index === -1 || index < result.index) {
          result.index = index;
          result.sentenceStop = sentenceStops[i];
        }
      }
      return result;
    }
 
    var lastCandidate = {index: 0, sentenceStop: ''};
    while (true) {
      lastCandidate = getNextSentenceStop(
        node.value, lastCandidate.index + lastCandidate.sentenceStop.length);
      // abort if no more sentence stops are found
      if (lastCandidate.index === -1) {
        break;
      }
      // ignore if the sentence stop is the last character
      if (lastCandidate.index >= node.value.length - 1) {
        continue;
      }
      // ignore if the next character is not a space
      if (node.value.charAt(lastCandidate.index + lastCandidate.sentenceStop.length) !== ' ') {
        continue;
      }
      // ignore if the sentence stop (and its preceeding characters match a blacklisted string
      var isBlacklisted = false;
      for (var i = 0; i < blacklist.length; ++i) {
        var needle = blacklist[i];
        var startIndex = lastCandidate.index + lastCandidate.sentenceStop.length - needle.length;
        if (node.value.substr(startIndex, needle.length) == needle) {
          isBlacklisted = true;
          break;
        }
      }
      if (isBlacklisted) {
        continue;
      }
 
      file.warn(
        'Newline should follow end of sentence',
        file.offsetToPosition(file.positionToOffset(node.position.start) + lastCandidate.index)
      );
    }
 
  });
 
  done();
}
 
module.exports = {
  'sentence-newline': sentenceNewline
};