detect-indent
Advanced tools
Comparing version
136
index.js
'use strict'; | ||
// detect either spaces or tabs but not both to properly handle tabs | ||
// for indentation and spaces for alignment | ||
const INDENT_RE = /^(?:( )+|\t+)/; | ||
// Detect either spaces or tabs but not both to properly handle tabs for indentation and spaces for alignment | ||
const INDENT_REGEX = /^(?:( )+|\t+)/; | ||
@@ -12,14 +11,7 @@ function getMostUsed(indents) { | ||
for (const entry of indents) { | ||
// TODO: use destructuring when targeting Node.js 6 | ||
const key = entry[0]; | ||
const val = entry[1]; | ||
const u = val[0]; | ||
const w = val[1]; | ||
if (u > maxUsed || (u === maxUsed && w > maxWeight)) { | ||
maxUsed = u; | ||
maxWeight = w; | ||
result = Number(key); | ||
for (const [key, [usedCount, weight]] of indents) { | ||
if (usedCount > maxUsed || (usedCount === maxUsed && weight > maxWeight)) { | ||
maxUsed = usedCount; | ||
maxWeight = weight; | ||
result = key; | ||
} | ||
@@ -31,34 +23,28 @@ } | ||
module.exports = str => { | ||
if (typeof str !== 'string') { | ||
module.exports = string => { | ||
if (typeof string !== 'string') { | ||
throw new TypeError('Expected a string'); | ||
} | ||
// used to see if tabs or spaces are the most used | ||
let tabs = 0; | ||
let spaces = 0; | ||
// Remember the size of previous line's indentation | ||
let previousSize = 0; | ||
let previousIndentType; | ||
// remember the size of previous line's indentation | ||
let prev = 0; | ||
// 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 | ||
// 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 = { | ||
// 3: [1, 0], | ||
// 4: [1, 5], | ||
// 5: [1, 0], | ||
// 12: [1, 0], | ||
// t3: [1, 0], | ||
// t4: [1, 5], | ||
// s5: [1, 0], | ||
// s12: [1, 0], | ||
// } | ||
const indents = new Map(); | ||
// pointer to the array of last used indent | ||
let current; | ||
// whether the last action was an indent (opposed to an unindent) | ||
let isIndent; | ||
for (const line of str.split(/\n/g)) { | ||
for (const line of string.split(/\n/g)) { | ||
if (!line) { | ||
// ignore empty lines | ||
// Ignore empty lines | ||
continue; | ||
@@ -68,51 +54,67 @@ } | ||
let indent; | ||
const matches = line.match(INDENT_RE); | ||
let indentType; | ||
let weight; | ||
let entry; | ||
const matches = line.match(INDENT_REGEX); | ||
if (matches) { | ||
if (matches === null) { | ||
previousSize = 0; | ||
previousIndentType = ''; | ||
} else { | ||
indent = matches[0].length; | ||
if (matches[1]) { | ||
spaces++; | ||
indentType = 's'; | ||
} else { | ||
tabs++; | ||
indentType = 't'; | ||
} | ||
} else { | ||
indent = 0; | ||
} | ||
const diff = indent - prev; | ||
prev = indent; | ||
if (indentType !== previousIndentType) { | ||
previousSize = 0; | ||
} | ||
if (diff) { | ||
// an indent or unindent has been detected | ||
previousIndentType = indentType; | ||
isIndent = diff > 0; | ||
weight = 0; | ||
current = indents.get(isIndent ? diff : -diff); | ||
const indentDifference = indent - previousSize; | ||
previousSize = indent; | ||
if (current) { | ||
current[0]++; | ||
// Previous line have same indent? | ||
if (indentDifference === 0) { | ||
weight++; | ||
// We use the key from previous loop | ||
} else { | ||
current = [1, 0]; | ||
indents.set(diff, current); | ||
key = indentType + String(indentDifference > 0 ? indentDifference : -indentDifference); | ||
} | ||
} else if (current) { | ||
// if the last action was an indent, increment the weight | ||
current[1] += Number(isIndent); | ||
// 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 amount = getMostUsed(indents); | ||
const result = getMostUsed(indents); | ||
let amount = 0; | ||
let type; | ||
let indent; | ||
if (!amount) { | ||
type = null; | ||
indent = ''; | ||
} else if (spaces >= tabs) { | ||
type = 'space'; | ||
indent = ' '.repeat(amount); | ||
} else { | ||
type = 'tab'; | ||
indent = '\t'.repeat(amount); | ||
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); | ||
} | ||
} | ||
@@ -119,0 +121,0 @@ |
{ | ||
"name": "detect-indent", | ||
"version": "5.0.0", | ||
"description": "Detect the indentation of code", | ||
"license": "MIT", | ||
"repository": "sindresorhus/detect-indent", | ||
"author": { | ||
"name": "Sindre Sorhus", | ||
"email": "sindresorhus@gmail.com", | ||
"url": "sindresorhus.com" | ||
}, | ||
"engines": { | ||
"node": ">=4" | ||
}, | ||
"scripts": { | ||
"test": "xo && ava" | ||
}, | ||
"files": [ | ||
"index.js" | ||
], | ||
"keywords": [ | ||
"indent", | ||
"indentation", | ||
"detect", | ||
"infer", | ||
"identify", | ||
"code", | ||
"string", | ||
"text", | ||
"source", | ||
"space", | ||
"tab" | ||
], | ||
"devDependencies": { | ||
"ava": "*", | ||
"xo": "*" | ||
}, | ||
"xo": { | ||
"esnext": true | ||
} | ||
"name": "detect-indent", | ||
"version": "6.0.0", | ||
"description": "Detect the indentation of code", | ||
"license": "MIT", | ||
"repository": "sindresorhus/detect-indent", | ||
"author": { | ||
"name": "Sindre Sorhus", | ||
"email": "sindresorhus@gmail.com", | ||
"url": "sindresorhus.com" | ||
}, | ||
"engines": { | ||
"node": ">=8" | ||
}, | ||
"scripts": { | ||
"test": "xo && ava && tsd" | ||
}, | ||
"files": [ | ||
"index.js", | ||
"index.d.ts" | ||
], | ||
"keywords": [ | ||
"indent", | ||
"indentation", | ||
"detect", | ||
"infer", | ||
"identify", | ||
"code", | ||
"string", | ||
"text", | ||
"source", | ||
"space", | ||
"tab" | ||
], | ||
"devDependencies": { | ||
"ava": "^1.4.1", | ||
"tsd": "^0.7.2", | ||
"xo": "^0.24.0" | ||
}, | ||
"xo": { | ||
"ignores": [ | ||
"fixture" | ||
] | ||
} | ||
} |
@@ -18,3 +18,3 @@ # detect-indent [](https://travis-ci.org/sindresorhus/detect-indent) | ||
``` | ||
$ npm install --save detect-indent | ||
$ npm install detect-indent | ||
``` | ||
@@ -38,3 +38,3 @@ | ||
// tries to detect the indentation and falls back to a default if it can't | ||
// Tries to detect the indentation and falls back to a default if it can't | ||
const indent = detectIndent(file).indent || ' '; | ||
@@ -60,3 +60,3 @@ | ||
* `amount` {number} - Amount of indentation, for example `2` | ||
* `type` {string|null} - Type of indentation. Possible values are `tab`, `space` or `null` if no indentation is detected | ||
* `type` {'tab' | 'space' | undefined} - Type of indentation. Possible values are `'tab'`, `'space'` or `undefined` if no indentation is detected | ||
* `indent` {string} - Actual indentation | ||
@@ -110,2 +110,3 @@ | ||
- [detect-newline](https://github.com/sindresorhus/detect-newline) - Detect the dominant newline character of a string | ||
- [detect-indent-rs](https://github.com/stefanpenner/detect-indent-rs) - Rust port | ||
@@ -112,0 +113,0 @@ |
Sorry, the diff of this file is not supported yet
7836
20.42%5
25%138
40.82%113
0.89%3
50%