/
index.js
123 lines (99 loc) · 2.45 KB
/
index.js
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
'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 as occurred for a given size and how much 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
};
};