125 lines
2.5 KiB
JavaScript
125 lines
2.5 KiB
JavaScript
'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
|
|
};
|
|
};
|