Skip to content
140 changes: 140 additions & 0 deletions src/Formatter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,146 @@ describe('Formatter', () => {
end sub
`);
});

it('formats outdents', () => {
Comment thread
TwitchBronBron marked this conversation as resolved.
expect(formatter.format(undent`
temp = {
key_9: { env: ["any"], themes: ["any"], runtimeCheck: function() as boolean
return true
end function }
}
`, {
formatMultiLineObjectsAndArrays: false
})).to.equal(undent`
temp = {
key_9: { env: ["any"], themes: ["any"], runtimeCheck: function() as boolean
return true
end function }
}
`);

expect(formatter.format(undent`
function test()
temp = {
key_9: { env: ["any"], themes: ["any"], runtimeCheck: function() as boolean
return true
end function
}
}
end function
`, {
formatMultiLineObjectsAndArrays: false
})).to.equal(undent`
function test()
temp = {
key_9: { env: ["any"], themes: ["any"], runtimeCheck: function() as boolean
return true
end function
}
}
end function
`);

expect(formatter.format(undent`
function test()
temp = {
key_9: {
env: ["any"], themes: ["any"], runtimeCheck: function() as boolean
return true
end function
}
}
end function
`, {
formatMultiLineObjectsAndArrays: false
})).to.equal(undent`
function test()
temp = {
key_9: {
env: ["any"], themes: ["any"], runtimeCheck: function() as boolean
return true
end function
}
}
end function
`);

expect(formatter.format(undent`
namespace tests
class TestStuff
function _()
m.assertEqual(sanitize({
key_0: { env: [], themes: ["any"] }
key_1: { env: ["any"], themes: ["test"] }
key_2: { env: ["prod"], themes: ["test"] }
key_3: { env: ["prod"], themes: ["test"] }
key_4: { env: ["prod", "qa"], themes: ["test", "test"] }
key_5: { env: ["dev", "qa"], themes: ["test"] }
key_6: { env: ["dev", "qa"], themes: ["test", "test"] }
key_7: { env: ["dev", "qa"], themes: ["test"] }
key_8: { env: [], themes: [] }
key_9: { env: ["any"], themes: ["any"], runtimeCheck: function() as boolean
return true
end function }
key_10: { env: ["any"], themes: ["any"], runtimeCheck: function() as boolean
return false
end function }
key_11: { env: ["dev"], themes: ["any"], runtimeCheck: function() as boolean
return true
end function }
key_12: { env: ["any"], themes: ["test"], runtimeCheck: function() as boolean
return true
end function }
key_13: { { env: ["any"], themes: ["test"], runtimeCheck: function() as boolean
return true
end function } }
}, "prod", "test"), {
enabled: ["key_1", "key_2", "key_4", "key_9"]
available: ["key_0", "key_1", "key_10", "key_11", "key_12", "key_2", "key_3", "key_4", "key_5", "key_6", "key_7", "key_8", "key_9"]
})
end function
end class
end namespace
`, {
formatMultiLineObjectsAndArrays: false
})).to.equal(undent`
namespace tests
class TestStuff
function _()
m.assertEqual(sanitize({
key_0: { env: [], themes: ["any"] }
key_1: { env: ["any"], themes: ["test"] }
key_2: { env: ["prod"], themes: ["test"] }
key_3: { env: ["prod"], themes: ["test"] }
key_4: { env: ["prod", "qa"], themes: ["test", "test"] }
key_5: { env: ["dev", "qa"], themes: ["test"] }
key_6: { env: ["dev", "qa"], themes: ["test", "test"] }
key_7: { env: ["dev", "qa"], themes: ["test"] }
key_8: { env: [], themes: [] }
key_9: { env: ["any"], themes: ["any"], runtimeCheck: function() as boolean
return true
end function }
key_10: { env: ["any"], themes: ["any"], runtimeCheck: function() as boolean
return false
end function }
key_11: { env: ["dev"], themes: ["any"], runtimeCheck: function() as boolean
return true
end function }
key_12: { env: ["any"], themes: ["test"], runtimeCheck: function() as boolean
return true
end function }
key_13: { { env: ["any"], themes: ["test"], runtimeCheck: function() as boolean
return true
end function } }
}, "prod", "test"), {
enabled: ["key_1", "key_2", "key_4", "key_9"]
available: ["key_0", "key_1", "key_10", "key_11", "key_12", "key_2", "key_3", "key_4", "key_5", "key_6", "key_7", "key_8", "key_9"]
})
end function
end class
end namespace
`);
});
});

describe('formatMultiLineObjectsAndArrays', () => {
Expand Down
59 changes: 59 additions & 0 deletions src/formatters/IndentFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export class IndentFormatter {
let currentLineOffset = 0;
let nextLineOffset = 0;
let foundIndentorThisLine = false;
let outdentCount = 0;

for (let i = 0; i < lineTokens.length; i++) {
let token = lineTokens[i];
Expand Down Expand Up @@ -151,6 +152,10 @@ export class IndentFormatter {
}

nextLineOffset--;
if (OutdentSpacerTokenKinds.includes(token.kind)) {
outdentCount++;
}

if (foundIndentorThisLine === false) {
currentLineOffset--;
}
Expand Down Expand Up @@ -189,12 +194,66 @@ export class IndentFormatter {
// tabCount--;
// }
}

//check if next multiple indents are followed by multiple outdents and update indentation accordingly
if (nextLineOffset > 1) {
nextLineOffset = this.lookaheadSameLineMultiOutdents(tokens, lineTokens[lineTokens.length - 1], nextLineOffset, currentLineOffset);
} else if (outdentCount > 0) {
//if multiple outdents on same line then outdent only once
if (currentLineOffset < 0) {
currentLineOffset = -1;
}

//if multiple outdents on same line then outdent nextline only once
if (nextLineOffset < 0) {
nextLineOffset = -1;
}
}

return {
currentLineOffset: currentLineOffset,
nextLineOffset: nextLineOffset
};
}

/**
* Lookahead if next line with oudents are same as indents on current line
* @param tokens the array of tokens in a file
* @param curLineToken token of curent line
* @param nextLineOffset the number of tabs to indent the next line
* @param currentLineOffset the number of tabs to indent the current line
*/
private lookaheadSameLineMultiOutdents(tokens: Token[], curLineToken: Token, nextLineOffset: number, currentLineOffset: number): number {
let outdentCount = 0;
let tokenLineNum = 0;
let currentLineTokenIndex = tokens.indexOf(curLineToken);

for (let i = currentLineTokenIndex + 1; i < tokens.length; i++) {
let token = tokens[i];
if (token.kind !== TokenKind.Whitespace) {
//next line with outdents
if (OutdentSpacerTokenKinds.includes(token.kind)) {
if (tokenLineNum === 0) {
tokenLineNum = token.range.start.line;
}

if (token.range.start.line === tokenLineNum) {
outdentCount++;
}
}
if (tokenLineNum > 0 && token.range.start.line !== tokenLineNum) {
break;
}
}
}

//if outdents on next line with outdents = indents on current line then indent next line by one tab only
if (outdentCount > 0 && outdentCount === nextLineOffset) {
nextLineOffset = currentLineOffset + 1;
}
return nextLineOffset;
}

/**
* Ensure the list of tokens contains the correct number of tabs
* @param tokens the array of tokens to be modified in-place
Expand Down