Skip to content
This repository has been archived by the owner on May 1, 2020. It is now read-only.

Commit

Permalink
Added option to remove trailing whitespace
Browse files Browse the repository at this point in the history
  • Loading branch information
TwitchBronBron committed Jul 9, 2018
1 parent fb844bc commit de4b96d
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 38 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ var formattedFileContents = formatter.format(unformattedFileContents, formatting


## Formatting Options
Click [here](https://github.com/TwitchBronBron/brightscript-formatter/blob/master/src/BrightScriptFormatter.ts#L265) to view all of the formatting options
Click [here](https://github.com/TwitchBronBron/brightscript-formatter/blob/master/src/BrightScriptFormatter.ts#L368) to view all of the formatting options

## Known issues

Expand Down
13 changes: 11 additions & 2 deletions dist/BrightScriptFormatter.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ export declare class BrightScriptFormatter {
private getCompositeKeywordParts(token);
private formatKeywordCasing(tokens, options);
private formatIndentation(tokens, options);
/**
* Remove all trailing whitespace
*/
private formatTrailingWhiteSpace(tokens, options);
private tokenIndexOf(tokenType, tokens);
/**
* Get the tokens for the whole line starting at the given index
* Get the tokens for the whole line starting at the given index (including the newline or EOF token at the end)
* @param startIndex
* @param tokens
*/
Expand All @@ -36,7 +40,7 @@ export interface FormattingOptions {
/**
* The type of indentation to use when indenting the beginning of lines.
*/
indentStyle?: 'tabs' | 'spaces' | null;
indentStyle?: 'tabs' | 'spaces' | 'existing';
/**
* The number of spaces to use when indentStyle is 'spaces'. Default is 4
*/
Expand All @@ -53,4 +57,9 @@ export interface FormattingOptions {
* If null, they are not modified.
*/
compositeKeywords?: 'split' | 'combine' | null;
/**
* If true (the default), trailing white space is removed
* If false, trailing white space is left intact
*/
removeTrailingWhiteSpace?: boolean;
}
92 changes: 60 additions & 32 deletions dist/BrightScriptFormatter.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
Object.defineProperty(exports, "__esModule", {
value: true
});
var brightscript_parser_1 = require("brightscript-parser");
var trimRight = require("trim-right");
var BrightScriptFormatter = /** @class */ (function () {
function BrightScriptFormatter() {
}
function BrightScriptFormatter() {}
/**
* Format the given input.
* @param inputText the text to format
Expand All @@ -24,6 +26,9 @@ var BrightScriptFormatter = /** @class */ (function () {
if (options.keywordCase) {
tokens = this.formatKeywordCasing(tokens, options);
}
if (options.removeTrailingWhiteSpace) {
tokens = this.formatTrailingWhiteSpace(tokens, options);
}
//join all tokens back together into a single string
var outputText = '';
for (var _i = 0, tokens_1 = tokens; _i < tokens_1.length; _i++) {
Expand Down Expand Up @@ -63,8 +68,7 @@ var BrightScriptFormatter = /** @class */ (function () {
var tokenValue = token.value;
if (options.compositeKeywords === 'combine') {
token.value = parts[0] + parts[1];
}
else {
} else {
token.value = parts[0] + ' ' + parts[1];
}
var offsetDifference = token.value.length - tokenValue.length;
Expand All @@ -78,8 +82,7 @@ var BrightScriptFormatter = /** @class */ (function () {
//split the parts of the token, but retain their case
if (lowerValue.indexOf('end') === 0) {
return [token.value.substring(0, 3), token.value.substring(3).trim()];
}
else {
} else {
return [token.value.substring(0, 4), token.value.substring(4).trim()];
}
};
Expand All @@ -99,27 +102,25 @@ var BrightScriptFormatter = /** @class */ (function () {
var lowerValue = token.value.toLowerCase();
if (brightscript_parser_1.CompositeKeywordTokenTypes.indexOf(token.tokenType) === -1) {
token.value = token.value.substring(0, 1).toUpperCase() + token.value.substring(1).toLowerCase();
}
else {
} else {
var spaceCharCount = (lowerValue.match(/\s+/) || []).length;
var firstWordLength = 0;
if (lowerValue.indexOf('end') === 0) {
firstWordLength = 3;
}
else {
} else {
firstWordLength = 4;
}
token.value =
//first character
token.value.substring(0, 1).toUpperCase() +
//rest of first word
token.value.substring(1, firstWordLength).toLowerCase() +
//add back the whitespace
token.value.substring(firstWordLength, firstWordLength + spaceCharCount) +
//first character of second word
token.value.substring(firstWordLength + spaceCharCount, firstWordLength + spaceCharCount + 1).toUpperCase() +
//rest of second word
token.value.substring(firstWordLength + spaceCharCount + 1).toLowerCase();
//rest of first word
token.value.substring(1, firstWordLength).toLowerCase() +
//add back the whitespace
token.value.substring(firstWordLength, firstWordLength + spaceCharCount) +
//first character of second word
token.value.substring(firstWordLength + spaceCharCount, firstWordLength + spaceCharCount + 1).toUpperCase() +
//rest of second word
token.value.substring(firstWordLength + spaceCharCount + 1).toLowerCase();
}
}
}
Expand Down Expand Up @@ -169,24 +170,21 @@ var BrightScriptFormatter = /** @class */ (function () {
// } else {
// //do nothing with single-line if statement indentation
// }
}
else {
} else {
for (var _i = 0, lineTokens_1 = lineTokens; _i < lineTokens_1.length; _i++) {
var token = lineTokens_1[_i];
//if this is an indentor token,
if (indentTokens.indexOf(token.tokenType) > -1) {
tabCount++;
foundIndentorThisLine = true;
//this is an outdentor token
}
else if (outdentTokens.indexOf(token.tokenType) > -1) {
} else if (outdentTokens.indexOf(token.tokenType) > -1) {
tabCount--;
if (foundIndentorThisLine === false) {
thisTabCount--;
}
//this is an interum token
}
else if (interumTokens.indexOf(token.tokenType) > -1) {
} else if (interumTokens.indexOf(token.tokenType) > -1) {
//these need outdented, but don't change the tabCount
thisTabCount--;
}
Expand All @@ -204,8 +202,7 @@ var BrightScriptFormatter = /** @class */ (function () {
var indentSpaceCount = options.indentSpaceCount ? options.indentSpaceCount : BrightScriptFormatter.DEFAULT_INDENT_SPACE_COUNT;
var spaceCount = thisTabCount * indentSpaceCount;
leadingWhitespace = Array(spaceCount + 1).join(' ');
}
else {
} else {
leadingWhitespace = Array(thisTabCount + 1).join('\t');
}
//create a whitespace token if there isn't one
Expand All @@ -231,6 +228,37 @@ var BrightScriptFormatter = /** @class */ (function () {
}
return outputTokens;
};
/**
* Remove all trailing whitespace
*/
BrightScriptFormatter.prototype.formatTrailingWhiteSpace = function (tokens, options) {
var nextLineStartTokenIndex = 0;
//the list of output tokens
var outputTokens = [];
//set the loop to run for a max of double the number of tokens we found so we don't end up with an infinite loop
for (var outerLoopCounter = 0; outerLoopCounter <= tokens.length * 2; outerLoopCounter++) {
var lineObj = this.getLineTokens(nextLineStartTokenIndex, tokens);
nextLineStartTokenIndex = lineObj.stopIndex + 1;
var lineTokens = lineObj.tokens;
//the last token is newline or EOF, so the next-to-last token is where the trailing whitespace would reside
var potentialWhitespaceTokenIndex = lineTokens.length - 2;
var whitespaceTokenCandidate = lineTokens[potentialWhitespaceTokenIndex];
//if the final token is whitespace, throw it away
if (whitespaceTokenCandidate.tokenType === brightscript_parser_1.TokenType.whitespace) {
lineTokens.splice(potentialWhitespaceTokenIndex, 1);
//if the final token is a comment, trim the whitespace from the righthand side
} else if (whitespaceTokenCandidate.tokenType === brightscript_parser_1.TokenType.quoteComment || whitespaceTokenCandidate.tokenType === brightscript_parser_1.TokenType.remComment) {
whitespaceTokenCandidate.value = trimRight(whitespaceTokenCandidate.value);
}
//add this line to the output
outputTokens.push.apply(outputTokens, lineTokens);
//if we have found the end of file, quit the loop
if (lineTokens[lineTokens.length - 1].tokenType === brightscript_parser_1.TokenType.END_OF_FILE) {
break;
}
}
return outputTokens;
};
BrightScriptFormatter.prototype.tokenIndexOf = function (tokenType, tokens) {
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
Expand All @@ -241,7 +269,7 @@ var BrightScriptFormatter = /** @class */ (function () {
return -1;
};
/**
* Get the tokens for the whole line starting at the given index
* Get the tokens for the whole line starting at the given index (including the newline or EOF token at the end)
* @param startIndex
* @param tokens
*/
Expand All @@ -266,7 +294,8 @@ var BrightScriptFormatter = /** @class */ (function () {
indentStyle: 'spaces',
indentSpaceCount: BrightScriptFormatter.DEFAULT_INDENT_SPACE_COUNT,
keywordCase: 'lower',
compositeKeywords: 'split'
compositeKeywords: 'split',
removeTrailingWhiteSpace: true
};
if (options) {
for (var attrname in options) {
Expand Down Expand Up @@ -294,8 +323,7 @@ var BrightScriptFormatter = /** @class */ (function () {
var token = lineTokens[i];
if (token.tokenType === brightscript_parser_1.TokenType.whitespace || token.tokenType === brightscript_parser_1.TokenType.newline) {
//do nothing with whitespace and newlines
}
else {
} else {
//we encountered a non whitespace and non newline token, so this line must be a single-line if statement
return true;
}
Expand All @@ -308,4 +336,4 @@ var BrightScriptFormatter = /** @class */ (function () {
BrightScriptFormatter.DEFAULT_INDENT_SPACE_COUNT = 4;
return BrightScriptFormatter;
}());
exports.BrightScriptFormatter = BrightScriptFormatter;
exports.BrightScriptFormatter = BrightScriptFormatter;
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
},
"homepage": "https://github.com/TwitchBronBron/brightscript-formatter#readme",
"dependencies": {
"brightscript-parser": "^1.0.3-1"
"brightscript-parser": "^1.0.3-1",
"trim-right": "^1.0.1"
},
"devDependencies": {
"@types/chai": "^4.1.2",
Expand Down
29 changes: 29 additions & 0 deletions src/BrightScriptFormatter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,35 @@ describe('BrightScriptFormatter', () => {
});
});

describe('removeTrailingWhitespace', () => {
it('removes trailing spaces by default', () => {
expect(formatter.format(`name = "bob" `)).to.equal(`name = "bob"`);
});
it('removes trailing tabs by default', () => {
expect(formatter.format(`name = "bob"\t`)).to.equal(`name = "bob"`);
});
it('removes both tabs and spaces in same line', () => {
expect(formatter.format(`name = "bob"\t `)).to.equal(`name = "bob"`);
expect(formatter.format(`name = "bob" \t`)).to.equal(`name = "bob"`);
});
it('removes whitespace from end of comment', () => {
expect(formatter.format(`'comment `)).to.equal(`'comment`);
expect(formatter.format(`'comment\t`)).to.equal(`'comment`);
expect(formatter.format(`'comment \t`)).to.equal(`'comment`);
expect(formatter.format(`'comment\t `)).to.equal(`'comment`);
});
it('handles multi-line prorgams', () => {
expect(formatter.format(`name = "bob"\t \nage=22 `)).to.equal(`name = "bob"\nage=22`);
});
it('leaves normal programs alone', () => {
expect(formatter.format(`name = "bob"\nage=22 `)).to.equal(`name = "bob"\nage=22`);
});
it('skips formatting when the option is set to false', () => {
expect(formatter.format(`name = "bob" `, { removeTrailingWhiteSpace: false })).to.equal(`name = "bob" `);

});
});

describe('break composite keywords', () => {
function format(text, tokenType) {
let token = {
Expand Down
54 changes: 52 additions & 2 deletions src/BrightScriptFormatter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { BrightScriptLexer, CompositeKeywordTokenTypes, KeywordTokenTypes, Token, TokenType } from 'brightscript-parser';
import * as trimRight from 'trim-right';

export class BrightScriptFormatter {
constructor() {

Expand Down Expand Up @@ -31,6 +33,9 @@ export class BrightScriptFormatter {
if (options.keywordCase) {
tokens = this.formatKeywordCasing(tokens, options);
}
if (options.removeTrailingWhiteSpace) {
tokens = this.formatTrailingWhiteSpace(tokens, options);
}

//join all tokens back together into a single string
let outputText = '';
Expand Down Expand Up @@ -243,6 +248,44 @@ export class BrightScriptFormatter {
return outputTokens;
}

/**
* Remove all trailing whitespace
*/
private formatTrailingWhiteSpace(tokens: Token[], options: FormattingOptions) {
let nextLineStartTokenIndex = 0;
//the list of output tokens
let outputTokens: Token[] = [];

//set the loop to run for a max of double the number of tokens we found so we don't end up with an infinite loop
for (let outerLoopCounter = 0; outerLoopCounter <= tokens.length * 2; outerLoopCounter++) {
let lineObj = this.getLineTokens(nextLineStartTokenIndex, tokens);

nextLineStartTokenIndex = lineObj.stopIndex + 1;
let lineTokens = lineObj.tokens;
//the last token is newline or EOF, so the next-to-last token is where the trailing whitespace would reside
let potentialWhitespaceTokenIndex = lineTokens.length - 2;

let whitespaceTokenCandidate = lineTokens[potentialWhitespaceTokenIndex];
//if the final token is whitespace, throw it away
if (whitespaceTokenCandidate.tokenType === TokenType.whitespace) {
lineTokens.splice(potentialWhitespaceTokenIndex, 1);

//if the final token is a comment, trim the whitespace from the righthand side
} else if (whitespaceTokenCandidate.tokenType === TokenType.quoteComment || whitespaceTokenCandidate.tokenType === TokenType.remComment) {
whitespaceTokenCandidate.value = trimRight(whitespaceTokenCandidate.value);
}

//add this line to the output
outputTokens.push.apply(outputTokens, lineTokens);

//if we have found the end of file, quit the loop
if (lineTokens[lineTokens.length - 1].tokenType === TokenType.END_OF_FILE) {
break;
}
}
return outputTokens;
}

private tokenIndexOf(tokenType: TokenType, tokens: Token[]) {
for (let i = 0; i < tokens.length; i++) {
let token = tokens[i];
Expand All @@ -254,7 +297,7 @@ export class BrightScriptFormatter {
}

/**
* Get the tokens for the whole line starting at the given index
* Get the tokens for the whole line starting at the given index (including the newline or EOF token at the end)
* @param startIndex
* @param tokens
*/
Expand All @@ -281,7 +324,8 @@ export class BrightScriptFormatter {
indentStyle: 'spaces',
indentSpaceCount: BrightScriptFormatter.DEFAULT_INDENT_SPACE_COUNT,
keywordCase: 'lower',
compositeKeywords: 'split'
compositeKeywords: 'split',
removeTrailingWhiteSpace: true
};
if (options) {
for (let attrname in options) {
Expand Down Expand Up @@ -342,4 +386,10 @@ export interface FormattingOptions {
* If null, they are not modified.
*/
compositeKeywords?: 'split' | 'combine' | null;
/**
* If true (the default), trailing white space is removed
* If false, trailing white space is left intact
*/
removeTrailingWhiteSpace?: boolean;

}

1 comment on commit de4b96d

@TwitchBronBron
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes #9

Please sign in to comment.