123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- /* 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
- };
- };
|