123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- 'use strict';
-
- // Detect either spaces or tabs but not both to properly handle tabs for indentation and spaces for alignment
- const INDENT_REGEX = /^(?:( )+|\t+)/;
-
- function getMostUsed(indents) {
- let result = 0;
- let maxUsed = 0;
- let maxWeight = 0;
-
- for (const [key, [usedCount, weight]] of indents) {
- if (usedCount > maxUsed || (usedCount === maxUsed && weight > maxWeight)) {
- maxUsed = usedCount;
- maxWeight = weight;
- result = key;
- }
- }
-
- return result;
- }
-
- module.exports = string => {
- if (typeof string !== 'string') {
- throw new TypeError('Expected a string');
- }
-
- // Remember the size of previous line's indentation
- let previousSize = 0;
- let previousIndentType;
-
- // Indents key (ident type + size of the indents/unindents)
- let key;
-
- // Remember how many indents/unindents have occurred for a given size and how many lines follow a given indentation.
- // The key is a concatenation of the indentation type (s = space and t = tab) and the size of the indents/unindents.
- //
- // indents = {
- // t3: [1, 0],
- // t4: [1, 5],
- // s5: [1, 0],
- // s12: [1, 0],
- // }
- const indents = new Map();
-
- for (const line of string.split(/\n/g)) {
- if (!line) {
- // Ignore empty lines
- continue;
- }
-
- let indent;
- let indentType;
- let weight;
- let entry;
- const matches = line.match(INDENT_REGEX);
-
- if (matches === null) {
- previousSize = 0;
- previousIndentType = '';
- } else {
- indent = matches[0].length;
-
- if (matches[1]) {
- indentType = 's';
- } else {
- indentType = 't';
- }
-
- if (indentType !== previousIndentType) {
- previousSize = 0;
- }
-
- previousIndentType = indentType;
-
- weight = 0;
-
- const indentDifference = indent - previousSize;
- previousSize = indent;
-
- // Previous line have same indent?
- if (indentDifference === 0) {
- weight++;
- // We use the key from previous loop
- } else {
- key = indentType + String(indentDifference > 0 ? indentDifference : -indentDifference);
- }
-
- // Update the stats
- entry = indents.get(key);
-
- if (entry === undefined) {
- entry = [1, 0]; // Init
- } else {
- entry = [++entry[0], entry[1] + weight];
- }
-
- indents.set(key, entry);
- }
- }
-
- const result = getMostUsed(indents);
-
- let amount = 0;
- let type;
- let indent = '';
-
- if (result !== 0) {
- amount = Number(result.slice(1));
-
- if (result[0] === 's') {
- type = 'space';
- indent = ' '.repeat(amount);
- } else {
- type = 'tab';
- indent = '\t'.repeat(amount);
- }
- }
-
- return {
- amount,
- type,
- indent
- };
- };
|