Skip to content

Commit b6aeeef

Browse files
committed
fix edge case issues with bracket counting
1 parent 5e76078 commit b6aeeef

13 files changed

+350
-4020
lines changed

.gitignore

+5-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1-
# Created by .ignore support plugin (hsz.mobi)
1+
node_modules
2+
.~
3+
*~
4+
coverage
5+
bower_components

file.js

-3,957
This file was deleted.

karma.conf.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module.exports = function(config){
2+
config.set({
3+
4+
basePath : './',
5+
6+
logLevel: config.LOG_DEBUG,
7+
8+
files : [
9+
'src/indent.js',
10+
'tests/utils.js',
11+
'tests/**/*.spec.js'
12+
],
13+
14+
exclude : [
15+
],
16+
17+
reporters: ['progress', 'coverage'],
18+
19+
preprocessors: {
20+
"src/indent.js": ['coverage']
21+
},
22+
23+
autoWatch : false,
24+
25+
frameworks: ['jasmine'],
26+
27+
browsers : ['PhantomJS'],
28+
29+
plugins : [
30+
'karma-jasmine',
31+
'karma-phantomjs-launcher',
32+
'karma-coverage'
33+
]
34+
});
35+
};

package.json

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "indent.js",
3+
"version": "0.1.0",
4+
"description": "Fast minimalistic auto indentation of JavaScript, CSS, and HTML.",
5+
"main": "indent.js",
6+
"directories": {
7+
"test": "tests"
8+
},
9+
"dependencies": {},
10+
"devDependencies": {
11+
"jasmine-core": "^2.2.0",
12+
"karma": "^0.12.31",
13+
"karma-coverage": "^0.3.1",
14+
"karma-jasmine": "^0.3.5",
15+
"karma-phantomjs-launcher": "^0.1.4",
16+
"gulp": "^3.9",
17+
"gulp-clean": "^0.3.1",
18+
"gulp-concat": "^2.6.0",
19+
"gulp-uglify": "^1.4.1"
20+
},
21+
"scripts": {
22+
"test": "karma start karma.conf.js --single-run",
23+
"start": "http-server -a localhost -p 8123 -c-1"
24+
},
25+
"repository": {
26+
"type": "git",
27+
"url": "git+https://[email protected]/jswriter/jsindenter.git"
28+
},
29+
"keywords": [
30+
"indent",
31+
"small",
32+
"reformat",
33+
"js",
34+
"css",
35+
"html"
36+
],
37+
"author": "Zeb Zhao",
38+
"license": "MIT",
39+
"homepage": "https://bitbucket.org/jswriter/jsindenter#readme"
40+
}

jsindent.js renamed to src/indent.js

+49-62
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
(function(exports) {
2-
exports.indenter = {
2+
exports.indent = {
33
indentCSS: indentJS,
44
indentJS: indentJS,
55
indentHTML: indentHTML
@@ -24,7 +24,7 @@
2424
{
2525
name: "regex",
2626
startToken: [function(string, rule) {
27-
var re = /[,=:!&|?};][\s]*\/[^/]|^\/[^/]/;
27+
var re = /[(,=:[!&|?{};][\s]*\/[^/]|^[\s]*\/[^/]/;
2828
var startIndex = string.search(re);
2929
if (startIndex != -1) {
3030
startIndex = string.indexOf('/', startIndex);
@@ -112,18 +112,11 @@
112112
},
113113
{
114114
name: "bracket",
115-
startToken: [/[^\(]\(/],
115+
startToken: [/\(/],
116116
endToken: [/\)/],
117117
indent: true,
118118
advance: true
119119
},
120-
{
121-
name: "bracket",
122-
startToken: [/^\(/],
123-
endToken: [/\)/],
124-
indent: false,
125-
advance: true
126-
},
127120
{
128121
name: "array",
129122
startToken: [/\[/],
@@ -141,7 +134,7 @@
141134
{
142135
name: "var",
143136
startToken: [/var[\s]+/],
144-
endToken: [/\;/, /\=/],
137+
endToken: [/\;/],
145138
indent: true
146139
},
147140
{
@@ -197,10 +190,10 @@
197190
var lines = code.split(/[\r]?\n/gi);
198191
var lineCount = lines.length;
199192
var newLines = [];
200-
var indents = 0;
201-
var indentAfter = 0;
193+
var indentBuffer = [];
202194
var activeRules = [];
203195
var lastRule;
196+
var indents = 0;
204197
var l = 0;
205198
var pos = 0;
206199
var matchEnd, matchStart;
@@ -216,17 +209,16 @@
216209
if (matchEnd.matchIndex == -1) {
217210
if (lastRule.ignore) {
218211
// last rule is still active, and it's telling us to ignore.
219-
newLines[l] = getIndentation() + line;
220212
incrementLine();
221213
continue;
222214
}
223215
}
224216
else if (lastRule.ignore || matchStart.matchIndex == -1 || matchEnd.matchIndex <= matchStart.matchIndex) {
225-
if (matchEnd.matchIndex == 0 && lastRule.indent) {
226-
indents--;
227-
}
228-
else if (lastRule.indent) {
229-
indentAfter--;
217+
if (lastRule.indent) {
218+
consumeIndentation();
219+
if (matchEnd.matchIndex == 0) {
220+
calculateIndents();
221+
}
230222
}
231223
pos = matchEnd.cursor;
232224
removeLastRule();
@@ -239,7 +231,6 @@
239231
}
240232
else {
241233
// No new token match end, no new match start
242-
newLines[l] = getIndentation() + line;
243234
incrementLine();
244235
}
245236
}
@@ -250,27 +241,59 @@
250241
pos = match.cursor;
251242
lastRule = match.rule;
252243
activeRules.push(lastRule);
253-
if (lastRule.indent) indentAfter++;
244+
if (lastRule.indent)
245+
incrementIndentation();
254246
}
255247

256248
function removeLastRule() {
257249
activeRules.pop();
258250
lastRule = activeRules[activeRules.length-1];
259251
}
260252

261-
function getIndentation() {
262-
return (new Array(indents+1)).join(indentation);
253+
function calculateIndents() {
254+
indents = 0;
255+
for (var b,i=0; i<indentBuffer.length; i++) {
256+
b = indentBuffer[i];
257+
if (b.open && b.line != l)
258+
indents++;
259+
}
263260
}
264261

265262
function incrementLine() {
263+
newLines[l] = repeatString(indentation, indents) + line;
266264
l++;
267265
pos = 0;
268-
if (indentAfter != 0) {
269-
indents += indentAfter;
270-
indentAfter = 0;
266+
calculateIndents();
267+
}
268+
269+
function incrementIndentation() {
270+
var matched = indentBuffer[indentBuffer.length-1];
271+
if (matched && matched.line == l) {
272+
matched.indent++;
273+
}
274+
else {
275+
indentBuffer.push({
276+
indent: 1,
277+
open: true,
278+
line: l
279+
});
280+
}
281+
}
282+
283+
function consumeIndentation() {
284+
var lastElem = indentBuffer[indentBuffer.length-1];
285+
if (lastElem) {
286+
lastElem.open = l == lastElem.line;
287+
if (--lastElem.indent <= 0) {
288+
indentBuffer.pop();
289+
}
271290
}
272291
}
273292
}
293+
294+
function repeatString(baseString, repeat) {
295+
return (new Array(repeat+1)).join(baseString);
296+
}
274297

275298
function cleanEscapedChars(string) {
276299
return string.replace(/\\(u[0-9A-Za-z]{4}|u\{[0-9A-Za-z]{1,6}]\}|x[0-9A-Za-z]{2}|.)/g, '0');
@@ -334,39 +357,3 @@
334357
};
335358
}
336359
})(this);
337-
338-
339-
function hereDoc(f) {
340-
return f.toString().
341-
replace(/^[^\/]+\/\*!?/, '').
342-
replace(/\*\/[^\/]+$/, '');
343-
}
344-
345-
var fs = require('fs');
346-
var self = this;
347-
var code = `
348-
`
349-
var doc = hereDoc(function() {/*!
350-
if ((insideRule || enteringConditionalGroup) &&
351-
!(lookBack("&") || foundNestedPseudoClass()) &&
352-
!lookBack("(")) {
353-
// 'property: value' delimiter
354-
// which could be in a conditional group query
355-
insidePropertyValue = true;
356-
output.push(':');
357-
print.singleSpace();
358-
}
359-
*/})
360-
361-
362-
console.log(
363-
self.indenter.indentJS(doc, ' ')
364-
);
365-
// fs.readFile( __dirname + '/file.js', function (err, data) {
366-
// if (err) {
367-
// throw err;
368-
// }
369-
// console.log(
370-
// self.indenter.indentJS(data.toString(), ' ')
371-
// );
372-
// });

tests/comment.spec.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
describe('comment.spec.js', function() {
2+
it('should ignore line comment', function() {
3+
var input = hereDoc(function() {/*!
4+
if (last_type !== 'TK_END_EXPR') {
5+
if ((last_type !== 'TK_START_EXPR' || !(current_token.type === 'TK_RESERVED' && in_array(current_token.text, ['var', 'let', 'const']))) && flags.last_text !== ':') {
6+
// no need to force newline on 'var': for (var x = 0...)
7+
if (current_token.type === 'TK_RESERVED' && current_token.text === 'if' && flags.last_text === 'else') {
8+
// no newline for } else if {
9+
output.space_before_token = true;
10+
} else {
11+
print_newline();
12+
}
13+
}
14+
}
15+
*/
16+
});
17+
var expected = hereDoc(function() {/*!
18+
if (last_type !== 'TK_END_EXPR') {
19+
if ((last_type !== 'TK_START_EXPR' || !(current_token.type === 'TK_RESERVED' && in_array(current_token.text, ['var', 'let', 'const']))) && flags.last_text !== ':') {
20+
// no need to force newline on 'var': for (var x = 0...)
21+
if (current_token.type === 'TK_RESERVED' && current_token.text === 'if' && flags.last_text === 'else') {
22+
// no newline for } else if {
23+
output.space_before_token = true;
24+
} else {
25+
print_newline();
26+
}
27+
}
28+
}
29+
30+
*/
31+
});
32+
expect(indent.indentJS(input, ' ')).toEqual(expected);
33+
});
34+
});

0 commit comments

Comments
 (0)