Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,22 @@ on:
- master
pull_request:

concurrency:
# We use the pull request number to ensure that each PR has a unique concurrency group. This prevents different PRs from interfering
# with each other, especially when multiple PRs originate from the same branch. If the pull request number is not available, we fall
# back to using the branch name (`github.head_ref`) or the full reference (`github.ref`), ensuring uniqueness.
#
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
ci:
runs-on: ${{ matrix.os }}
env:
NODE_OPTIONS: "--max-old-space-size=4096"
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@master
- uses: actions/setup-node@master
Expand Down
38 changes: 38 additions & 0 deletions src/formatters/MultiLineItemFormatter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

import { expect } from 'chai';
import { Formatter } from '../Formatter';
import { undent } from 'undent';

describe('MultiLineItemFormatter', () => {
let formatter: Formatter;
Expand All @@ -15,6 +16,27 @@ describe('MultiLineItemFormatter', () => {
expect(formatter.format(inputSameLine).trim()).to.equal(expectedSameLine.trim());
});

it('preserves isMatchingDoubleArrayOrArrayCurly [[ .. ]]', () => {
const input = undent`
[[1, 2, 3]
]`;
const expected = undent`
[
[1, 2, 3]
]`;
expect(formatter.format(input).trim()).to.equal(expected.trim());
});
it('preserves isMatchingDoubleArrayOrArrayCurly [{ .. }]', () => {
const input = undent`
[{1, 2, 3}
]`;
const expected = undent`
[
{ 1, 2, 3 }
]`;
expect(formatter.format(input).trim()).to.equal(expected.trim());
});

it('preserves return object on same line (multi-line content)', () => {
const input = `sub foo()\n return {\n a: 1\n }\nend sub`;
const expected = `sub foo()\n return {\n a: 1\n }\nend sub`;
Expand All @@ -26,4 +48,20 @@ describe('MultiLineItemFormatter', () => {
const expected = `sub foo()\n return { a: 1,\n b: 2\n }\nend sub`;
expect(formatter.format(input).trim()).to.equal(expected.trim());
});

it('preserves multiple open/close pairs that are unbalanced', () => {
const input = undent`
m.callback.Invoke([m, {
"event": event,
"data": data,
}])
`;
const expected = undent`
m.callback.Invoke([m, {
"event": event,
"data": data,
}])
`;
expect(formatter.format(input).trim()).to.equal(expected.trim());
});
});
38 changes: 36 additions & 2 deletions src/formatters/MultiLineItemFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export class MultiLineItemFormatter {
//is NOT array like `[[ ...\n ]]`, or `[{ ...\n }]`)
!this.isMatchingDoubleArrayOrArrayCurly(tokens, i) &&
//Don't reformat if the opening bracket or curly is on the same line as 'return'
!this.isReturnArrayOrCurlyOnSameLine(tokens, i)
!this.isReturnArrayOrCurlyOnSameLine(tokens, i) &&
//Don't reformat if there are multiple open/close pairs that are unbalanced
!this.isMultiUnbalancedOpenClosePair(tokens, i)
) {
tokens.splice(i + 1, 0, {
kind: TokenKind.Newline,
Expand Down Expand Up @@ -79,6 +81,38 @@ export class MultiLineItemFormatter {
return false;
}

/**
* Detects when a line has both unbalanced square brackets and curly braces,
* which indicates a pattern like `[m, {` that should not be reformatted.
* Scans tokens from the given index until a newline is found.
* @param tokens The array of tokens to scan.
* @param currentIndex The index to start scanning from.
* @returns {boolean} True if both curly and square brackets are unbalanced before a newline; otherwise, false.
*/
public isMultiUnbalancedOpenClosePair(tokens: Token[], currentIndex: number) {
let curlyOpenCount = 0;
let squareOpenCount = 0;

for (let i = currentIndex; i < tokens.length; i++) {
let token = tokens[i];
if (token.kind === TokenKind.Newline) {
break;
}

if (token.kind === TokenKind.LeftCurlyBrace) {
curlyOpenCount++;
} else if (token.kind === TokenKind.RightCurlyBrace) {
curlyOpenCount--;
} else if (token.kind === TokenKind.LeftSquareBracket) {
squareOpenCount++;
} else if (token.kind === TokenKind.RightSquareBracket) {
squareOpenCount--;
}
}

return curlyOpenCount > 0 && squareOpenCount > 0;
}

public isMatchingDoubleArrayOrArrayCurly(tokens: Token[], currentIndex: number) {
let token = tokens[currentIndex];
let nextNonWhitespaceToken = util.getNextNonWhitespaceToken(tokens, currentIndex, true);
Expand All @@ -94,11 +128,11 @@ export class MultiLineItemFormatter {
let closingToken = util.getClosingToken(tokens, currentIndex, TokenKind.LeftSquareBracket, TokenKind.RightSquareBracket);
//look at the previous token
let previous = closingToken && util.getPreviousNonWhitespaceToken(tokens, tokens.indexOf(closingToken), true);
/* istanbul ignore else (because I can't figure out how to make this happen but I think it's still necessary) */
if (previous && (previous.kind === TokenKind.RightSquareBracket || previous.kind === TokenKind.RightCurlyBrace)) {
return true;
}
}
return false;
}

/**
Expand Down