| /* eslint-disable guard-for-in */ |
| 'use strict'; |
| var repeating = require('repeating'); |
| |
| // detect either spaces or tabs but not both to properly handle tabs |
| // for indentation and spaces for alignment |
| var INDENT_RE = /^(?:( )+|\t+)/; |
| |
| function getMostUsed(indents) { |
| var result = 0; |
| var maxUsed = 0; |
| var maxWeight = 0; |
| |
| for (var n in indents) { |
| var indent = indents[n]; |
| var u = indent[0]; |
| var w = indent[1]; |
| |
| if (u > maxUsed || u === maxUsed && w > maxWeight) { |
| maxUsed = u; |
| maxWeight = w; |
| result = Number(n); |
| } |
| } |
| |
| return result; |
| } |
| |
| module.exports = function (str) { |
| if (typeof str !== 'string') { |
| throw new TypeError('Expected a string'); |
| } |
| |
| // used to see if tabs or spaces are the most used |
| var tabs = 0; |
| var spaces = 0; |
| |
| // remember the size of previous line's indentation |
| var prev = 0; |
| |
| // remember how many indents/unindents as occurred for a given size |
| // and how much lines follow a given indentation |
| // |
| // indents = { |
| // 3: [1, 0], |
| // 4: [1, 5], |
| // 5: [1, 0], |
| // 12: [1, 0], |
| // } |
| var indents = {}; |
| |
| // pointer to the array of last used indent |
| var current; |
| |
| // whether the last action was an indent (opposed to an unindent) |
| var isIndent; |
| |
| str.split(/\n/g).forEach(function (line) { |
| if (!line) { |
| // ignore empty lines |
| return; |
| } |
| |
| var indent; |
| var matches = line.match(INDENT_RE); |
| |
| if (!matches) { |
| indent = 0; |
| } else { |
| indent = matches[0].length; |
| |
| if (matches[1]) { |
| spaces++; |
| } else { |
| tabs++; |
| } |
| } |
| |
| var diff = indent - prev; |
| prev = indent; |
| |
| if (diff) { |
| // an indent or unindent has been detected |
| |
| isIndent = diff > 0; |
| |
| current = indents[isIndent ? diff : -diff]; |
| |
| if (current) { |
| current[0]++; |
| } else { |
| current = indents[diff] = [1, 0]; |
| } |
| } else if (current) { |
| // if the last action was an indent, increment the weight |
| current[1] += Number(isIndent); |
| } |
| }); |
| |
| var amount = getMostUsed(indents); |
| |
| var type; |
| var actual; |
| if (!amount) { |
| type = null; |
| actual = ''; |
| } else if (spaces >= tabs) { |
| type = 'space'; |
| actual = repeating(' ', amount); |
| } else { |
| type = 'tab'; |
| actual = repeating('\t', amount); |
| } |
| |
| return { |
| amount: amount, |
| type: type, |
| indent: actual |
| }; |
| }; |