From a1abbc5b8345a276edbdcbcf4a5fab93d83c0b97 Mon Sep 17 00:00:00 2001 From: "Christian G. Warden" Date: Tue, 7 Jan 2025 17:56:55 -0600 Subject: [PATCH] Line Comment Fixes Fix line comments at the beginning of classes with annotations. Strip trailing whitespace from line comments. --- formatter/comments_test.go | 12 ++- formatter/format_test.go | 206 ++----------------------------------- formatter/soql_test.go | 204 ++++++++++++++++++++++++++++++++++++ formatter/visitor.go | 12 ++- 4 files changed, 230 insertions(+), 204 deletions(-) create mode 100644 formatter/soql_test.go diff --git a/formatter/comments_test.go b/formatter/comments_test.go index 8122d72..1e39a66 100644 --- a/formatter/comments_test.go +++ b/formatter/comments_test.go @@ -12,7 +12,7 @@ import ( func TestComments(t *testing.T) { if testing.Verbose() { - log.SetLevel(log.DebugLevel) + log.SetLevel(log.TraceLevel) log.SetFormatter(&log.TextFormatter{ DisableQuote: true, }) @@ -78,6 +78,12 @@ System.debug('I am on a separate line!');`, // Country default value contact.MailingCountry == 'United States');`, }, + { + `// Test trailing whitespace + go();`, + `// Test trailing whitespace +go();`, + }, } for i, tt := range tests { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { @@ -105,7 +111,7 @@ System.debug('I am on a separate line!');`, func TestTrailingComments(t *testing.T) { if testing.Verbose() { - log.SetLevel(log.DebugLevel) + log.SetLevel(log.TraceLevel) log.SetFormatter(&log.TextFormatter{ DisableQuote: true, }) @@ -117,7 +123,7 @@ func TestTrailingComments(t *testing.T) { }{ { `private class T1Exception extends Exception {} //test`, - `private class T1Exception extends Exception {} //test`, + "private class T1Exception extends Exception {} //test\n", }, { `public class MyClass { public static void noop() {} diff --git a/formatter/format_test.go b/formatter/format_test.go index 7ad2ede..3ff1ed8 100644 --- a/formatter/format_test.go +++ b/formatter/format_test.go @@ -426,7 +426,7 @@ func TestMemberDeclaration(t *testing.T) { func TestCompilationUnit(t *testing.T) { if testing.Verbose() { - log.SetLevel(log.DebugLevel) + log.SetLevel(log.TraceLevel) log.SetFormatter(&log.TextFormatter{ DisableQuote: true, }) @@ -585,6 +585,15 @@ public class Top { }; }`, }, + { + `// Tests for Account triggers +@IsTest +public class A { +}`, + `// Tests for Account triggers +@IsTest +public class A {}`, + }, } for i, tt := range tests { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { @@ -609,198 +618,3 @@ public class Top { }) } } - -func TestSOQL(t *testing.T) { - if testing.Verbose() { - log.SetLevel(log.DebugLevel) - - } - tests := - []struct { - input string - output string - }{ - { - `[SELECT Account.Name, count(Id) FROM Contact WHERE AccountId IN : accounts.keySet() GROUP BY Account.Name]`, - `[ - SELECT - Account.Name, - COUNT(Id) - FROM - Contact - WHERE - AccountId IN :accounts.keySet() - GROUP BY Account.Name -]`}, - { - `[ SELECT - Id - FROM - Location__c - WHERE Id IN ( - SELECT - Location__c - FROM - Clinic__c - WHERE - Clinic_Type__c IN ('Clinic', 'Clinic - Remote NP') AND - Status__c = 'Confirmed' AND - Location__c != null AND - Start__c = YESTERDAY - ) - ]`, - `[ - SELECT - Id - FROM - Location__c - WHERE - Id IN ( - SELECT - Location__c - FROM - Clinic__c - WHERE - Clinic_Type__c IN ('Clinic', 'Clinic - Remote NP') AND - Status__c = 'Confirmed' AND - Location__c != null AND - Start__c = YESTERDAY - ) -]`}, - - { - `[ - SELECT - Name - FROM - My_Object__c - WHERE - Type__c = 'Virtual' AND - ( - Start__c = TODAY OR - Start__c = N_DAYS_AGO:7 OR - Start__c = N_DAYS_AGO:14 OR - Start__c = N_DAYS_AGO:21 OR - Start__c <= N_DAYS_AGO:28 - ) AND - Status__c = 'Confirmed' - ORDER BY - Start__c -];`, `[ - SELECT - Name - FROM - My_Object__c - WHERE - Type__c = 'Virtual' AND - ( - Start__c = TODAY OR - Start__c = N_DAYS_AGO:7 OR - Start__c = N_DAYS_AGO:14 OR - Start__c = N_DAYS_AGO:21 OR - Start__c <= N_DAYS_AGO:28 - ) AND - Status__c = 'Confirmed' - ORDER BY - Start__c -]`}, - { - `[SELECT Id FROM ClinicalEncounter WHERE Id = :encounters[0].Id ALL ROWS]`, - `[SELECT Id FROM ClinicalEncounter WHERE Id = :encounters[0].Id ALL ROWS]`, - }, - { - `[SELECT Id, SBQQ__Quote__c FROM SBQQ__QuoteLineGroup__c WHERE SBQQ__Quote__c IN :quoteIds ORDER BY SBQQ__Quote__c, SBQQ__Number__c]`, - `[ - SELECT - Id, - SBQQ__Quote__c - FROM - SBQQ__QuoteLineGroup__c - WHERE - SBQQ__Quote__c IN :quoteIds - ORDER BY - SBQQ__Quote__c, - SBQQ__Number__c -]`}, - { - `[SELECT OBJ1__c O1, OBJ2__c O2, OBJ3__c O3, SUM(OBJ4__c) O4, GROUPING(OBJ1__c) O1Group, GROUPING(OBJ2__c) O2Group, GROUPING(OBJ3__c) O3Group FROM OBJ4__c GROUP BY ROLLUP(OBJ1__c, OBJ2__c, OBJ3__c)]`, - `[ - SELECT - OBJ1__c O1, - OBJ2__c O2, - OBJ3__c O3, - SUM(OBJ4__c) O4, - GROUPING(OBJ1__c) O1Group, - GROUPING(OBJ2__c) O2Group, - GROUPING(OBJ3__c) O3Group - FROM - OBJ4__c - GROUP BY ROLLUP(OBJ1__c, OBJ2__c, OBJ3__c) -]`}, - { - `[SELECT Name, (SELECT Id, (SELECT Id, (SELECT Id, (SELECT Id FROM Child4 ) FROM Child3 ) FROM Child2 ) FROM Child1) FROM Parent]`, - `[ - SELECT - Name, - (SELECT - Id, - (SELECT - Id, - (SELECT - Id, - (SELECT - Id - FROM - Child4) - FROM - Child3) - FROM - Child2) - FROM - Child1) - FROM - Parent -]`}, - { - `[ SELECT convertCurrency(Amount) FROM Opportunity ]`, - `[SELECT CONVERTCURRENCY(Amount) FROM Opportunity]`, - }, - { - `[SELECT Amount, FORMAT(amount) Amt, convertCurrency(amount) convertedAmount, - FORMAT(convertCurrency(amount)) convertedCurrency FROM Opportunity where Id = '006R00000024gDtIAI']`, - `[ - SELECT - Amount, - FORMAT(amount) Amt, - CONVERTCURRENCY(amount) convertedAmount, - FORMAT(CONVERTCURRENCY(amount)) convertedCurrency - FROM - Opportunity - WHERE - Id = '006R00000024gDtIAI' -]`, - }, - { - `[SELECT FORMAT(MIN(closedate)) Amt FROM opportunity]`, - `[SELECT FORMAT(MIN(closedate)) Amt FROM opportunity]`, - }, - } - for _, tt := range tests { - input := antlr.NewInputStream(tt.input) - lexer := parser.NewApexLexer(input) - stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel) - - p := parser.NewApexParser(stream) - p.RemoveErrorListeners() - p.AddErrorListener(&testErrorListener{t: t}) - - v := NewFormatVisitor(stream) - out, ok := v.visitRule(p.SoqlLiteral()).(string) - if !ok { - t.Errorf("Unexpected result parsing apex") - } - if out != tt.output { - t.Errorf("unexpected format. expected:\n%s\ngot:\n%s\n", tt.output, out) - } - } -} diff --git a/formatter/soql_test.go b/formatter/soql_test.go new file mode 100644 index 0000000..8afbda6 --- /dev/null +++ b/formatter/soql_test.go @@ -0,0 +1,204 @@ +package formatter + +import ( + "testing" + + "github.com/antlr4-go/antlr/v4" + "github.com/octoberswimmer/apexfmt/parser" + log "github.com/sirupsen/logrus" +) + +func TestSOQL(t *testing.T) { + if testing.Verbose() { + log.SetLevel(log.DebugLevel) + + } + tests := + []struct { + input string + output string + }{ + { + `[SELECT Account.Name, count(Id) FROM Contact WHERE AccountId IN : accounts.keySet() GROUP BY Account.Name]`, + `[ + SELECT + Account.Name, + COUNT(Id) + FROM + Contact + WHERE + AccountId IN :accounts.keySet() + GROUP BY Account.Name +]`}, + { + `[ SELECT + Id + FROM + Location__c + WHERE Id IN ( + SELECT + Location__c + FROM + Clinic__c + WHERE + Clinic_Type__c IN ('Clinic', 'Clinic - Remote NP') AND + Status__c = 'Confirmed' AND + Location__c != null AND + Start__c = YESTERDAY + ) + ]`, + `[ + SELECT + Id + FROM + Location__c + WHERE + Id IN ( + SELECT + Location__c + FROM + Clinic__c + WHERE + Clinic_Type__c IN ('Clinic', 'Clinic - Remote NP') AND + Status__c = 'Confirmed' AND + Location__c != null AND + Start__c = YESTERDAY + ) +]`}, + + { + `[ + SELECT + Name + FROM + My_Object__c + WHERE + Type__c = 'Virtual' AND + ( + Start__c = TODAY OR + Start__c = N_DAYS_AGO:7 OR + Start__c = N_DAYS_AGO:14 OR + Start__c = N_DAYS_AGO:21 OR + Start__c <= N_DAYS_AGO:28 + ) AND + Status__c = 'Confirmed' + ORDER BY + Start__c +];`, `[ + SELECT + Name + FROM + My_Object__c + WHERE + Type__c = 'Virtual' AND + ( + Start__c = TODAY OR + Start__c = N_DAYS_AGO:7 OR + Start__c = N_DAYS_AGO:14 OR + Start__c = N_DAYS_AGO:21 OR + Start__c <= N_DAYS_AGO:28 + ) AND + Status__c = 'Confirmed' + ORDER BY + Start__c +]`}, + { + `[SELECT Id FROM ClinicalEncounter WHERE Id = :encounters[0].Id ALL ROWS]`, + `[SELECT Id FROM ClinicalEncounter WHERE Id = :encounters[0].Id ALL ROWS]`, + }, + { + `[SELECT Id, SBQQ__Quote__c FROM SBQQ__QuoteLineGroup__c WHERE SBQQ__Quote__c IN :quoteIds ORDER BY SBQQ__Quote__c, SBQQ__Number__c]`, + `[ + SELECT + Id, + SBQQ__Quote__c + FROM + SBQQ__QuoteLineGroup__c + WHERE + SBQQ__Quote__c IN :quoteIds + ORDER BY + SBQQ__Quote__c, + SBQQ__Number__c +]`}, + { + `[SELECT OBJ1__c O1, OBJ2__c O2, OBJ3__c O3, SUM(OBJ4__c) O4, GROUPING(OBJ1__c) O1Group, GROUPING(OBJ2__c) O2Group, GROUPING(OBJ3__c) O3Group FROM OBJ4__c GROUP BY ROLLUP(OBJ1__c, OBJ2__c, OBJ3__c)]`, + `[ + SELECT + OBJ1__c O1, + OBJ2__c O2, + OBJ3__c O3, + SUM(OBJ4__c) O4, + GROUPING(OBJ1__c) O1Group, + GROUPING(OBJ2__c) O2Group, + GROUPING(OBJ3__c) O3Group + FROM + OBJ4__c + GROUP BY ROLLUP(OBJ1__c, OBJ2__c, OBJ3__c) +]`}, + { + `[SELECT Name, (SELECT Id, (SELECT Id, (SELECT Id, (SELECT Id FROM Child4 ) FROM Child3 ) FROM Child2 ) FROM Child1) FROM Parent]`, + `[ + SELECT + Name, + (SELECT + Id, + (SELECT + Id, + (SELECT + Id, + (SELECT + Id + FROM + Child4) + FROM + Child3) + FROM + Child2) + FROM + Child1) + FROM + Parent +]`}, + { + `[ SELECT convertCurrency(Amount) FROM Opportunity ]`, + `[SELECT CONVERTCURRENCY(Amount) FROM Opportunity]`, + }, + { + `[SELECT Amount, FORMAT(amount) Amt, convertCurrency(amount) convertedAmount, + FORMAT(convertCurrency(amount)) convertedCurrency FROM Opportunity where Id = '006R00000024gDtIAI']`, + `[ + SELECT + Amount, + FORMAT(amount) Amt, + CONVERTCURRENCY(amount) convertedAmount, + FORMAT(CONVERTCURRENCY(amount)) convertedCurrency + FROM + Opportunity + WHERE + Id = '006R00000024gDtIAI' +]`, + }, + { + `[SELECT FORMAT(MIN(closedate)) Amt FROM opportunity]`, + `[SELECT FORMAT(MIN(closedate)) Amt FROM opportunity]`, + }, + } + for _, tt := range tests { + input := antlr.NewInputStream(tt.input) + lexer := parser.NewApexLexer(input) + stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel) + + p := parser.NewApexParser(stream) + p.RemoveErrorListeners() + p.AddErrorListener(&testErrorListener{t: t}) + + v := NewFormatVisitor(stream) + out, ok := v.visitRule(p.SoqlLiteral()).(string) + if !ok { + t.Errorf("Unexpected result parsing apex") + } + if out != tt.output { + t.Errorf("unexpected format. expected:\n%s\ngot:\n%s\n", tt.output, out) + } + } +} diff --git a/formatter/visitor.go b/formatter/visitor.go index d4d822c..6a77406 100644 --- a/formatter/visitor.go +++ b/formatter/visitor.go @@ -375,18 +375,20 @@ func appendHiddenTokens(v *FormatVisitor, result interface{}, tokens []antlr.Tok } else if len(leadingWhitespace) > 0 && position == PositionAfter { leading = " " } + // Strip leading whitespace so the comment can be indented to the right location + containsNewline := strings.Contains(text, "\n") + text = strings.TrimSpace(text) + toEndOfLine := strings.HasPrefix(text, "//") + if n := countNewlines(trailingWhitespace); n > 0 { trailing = strings.Repeat("\n", n) - } else if len(trailingWhitespace) > 0 { + } else if len(trailingWhitespace) > 0 && !toEndOfLine { trailing = " " } - // Strip leading whitespace so the comment can be indented to the right location - containsNewline := strings.Contains(text, "\n") - text = strings.TrimSpace(text) text = fmt.Sprintf("%s%s%s", leading, text, trailing) log.Trace(fmt.Sprintf("NORMALIZED COMMENT: %q\n", text)) - if containsNewline { + if containsNewline || toEndOfLine { text = "\uFFFA" + text + "\uFFFB" + "\n" } else { text = "\uFFF9" + text + "\uFFFB"