tangled
alpha
login
or
join now
fuwn.net
/
iku
0
fork
atom
๐ Grammar-Aware Code Formatter: Structure through separation (supports Go, JavaScript, TypeScript, JSX, and TSX)
go
formatter
code-formatter
javascript
typescript
jsx
tsx
0
fork
atom
overview
issues
pulls
pipelines
refactor(formatter): Replace rewrite logic with engine
fuwn.net
1 month ago
acd264ee
30fb266c
verified
This commit was signed with the committer's
known signature
.
fuwn.net
SSH Key Fingerprint:
SHA256:VPdFPyPbd6JkoMyWUdZ/kkTcIAt3sxjXD2XSAZ7FYC4=
+5
-155
2 changed files
expand all
collapse all
unified
split
formatter.go
rewrite.go
+5
-15
formatter.go
···
1
1
package main
2
2
3
3
-
import (
4
4
-
"go/format"
5
5
-
"go/parser"
6
6
-
"go/token"
7
7
-
)
3
3
+
import "github.com/Fuwn/iku/engine"
8
4
9
5
type CommentMode int
10
6
···
26
22
}
27
23
28
24
func (f *Formatter) Format(source []byte) ([]byte, error) {
29
29
-
formattedSource, err := format.Source(source)
30
30
-
31
31
-
if err != nil {
32
32
-
return nil, err
33
33
-
}
34
34
-
35
35
-
tokenFileSet := token.NewFileSet()
36
36
-
parsedFile, err := parser.ParseFile(tokenFileSet, "", formattedSource, parser.ParseComments)
25
25
+
adapter := &GoAdapter{}
26
26
+
_, events, err := adapter.Analyze(source)
37
27
38
28
if err != nil {
39
29
return nil, err
40
30
}
41
31
42
42
-
lineInformationMap := f.buildLineInfo(tokenFileSet, parsedFile)
32
32
+
formattingEngine := &engine.Engine{CommentMode: MapCommentMode(f.CommentMode)}
43
33
44
44
-
return f.rewrite(formattedSource, lineInformationMap), nil
34
34
+
return []byte(formattingEngine.FormatToString(events)), nil
45
35
}
-140
rewrite.go
···
1
1
-
package main
2
2
-
3
3
-
import "strings"
4
4
-
5
5
-
func (f *Formatter) rewrite(formattedSource []byte, lineInformationMap map[int]*lineInformation) []byte {
6
6
-
sourceLines := strings.Split(string(formattedSource), "\n")
7
7
-
resultLines := make([]string, 0, len(sourceLines))
8
8
-
previousWasOpenBrace := false
9
9
-
previousStatementType := ""
10
10
-
previousWasComment := false
11
11
-
previousWasTopLevel := false
12
12
-
previousWasScoped := false
13
13
-
insideRawString := false
14
14
-
15
15
-
for lineIndex, currentLine := range sourceLines {
16
16
-
backtickCount := countRawStringDelimiters(currentLine)
17
17
-
wasInsideRawString := insideRawString
18
18
-
19
19
-
if backtickCount%2 == 1 {
20
20
-
insideRawString = !insideRawString
21
21
-
}
22
22
-
23
23
-
if wasInsideRawString {
24
24
-
resultLines = append(resultLines, currentLine)
25
25
-
26
26
-
continue
27
27
-
}
28
28
-
29
29
-
lineNumber := lineIndex + 1
30
30
-
trimmedLine := strings.TrimSpace(currentLine)
31
31
-
32
32
-
if trimmedLine == "" {
33
33
-
continue
34
34
-
}
35
35
-
36
36
-
isClosingBraceLine := isClosingBrace(currentLine)
37
37
-
isOpeningBraceLine := isOpeningBrace(currentLine)
38
38
-
isCaseLabelLine := isCaseLabel(currentLine)
39
39
-
isCommentOnlyLine := isCommentOnly(currentLine)
40
40
-
isPackageDeclaration := isPackageLine(trimmedLine)
41
41
-
currentInformation := lineInformationMap[lineNumber]
42
42
-
currentStatementType := ""
43
43
-
44
44
-
if currentInformation != nil {
45
45
-
currentStatementType = currentInformation.statementType
46
46
-
}
47
47
-
48
48
-
if isPackageDeclaration {
49
49
-
currentStatementType = "package"
50
50
-
}
51
51
-
52
52
-
needsBlankLine := false
53
53
-
currentIsTopLevel := currentInformation != nil && currentInformation.isTopLevel
54
54
-
currentIsScoped := currentInformation != nil && currentInformation.isScoped
55
55
-
56
56
-
if len(resultLines) > 0 && !previousWasOpenBrace && !isClosingBraceLine && !isCaseLabelLine {
57
57
-
if currentIsTopLevel && previousWasTopLevel && currentStatementType != previousStatementType {
58
58
-
if f.CommentMode == CommentsFollow && previousWasComment {
59
59
-
} else {
60
60
-
needsBlankLine = true
61
61
-
}
62
62
-
} else if currentInformation != nil && (currentIsScoped || previousWasScoped) {
63
63
-
if f.CommentMode == CommentsFollow && previousWasComment {
64
64
-
} else {
65
65
-
needsBlankLine = true
66
66
-
}
67
67
-
} else if currentStatementType != "" && previousStatementType != "" && currentStatementType != previousStatementType {
68
68
-
if f.CommentMode == CommentsFollow && previousWasComment {
69
69
-
} else {
70
70
-
needsBlankLine = true
71
71
-
}
72
72
-
}
73
73
-
74
74
-
if f.CommentMode == CommentsFollow && isCommentOnlyLine && !previousWasComment {
75
75
-
nextLineNumber := f.findNextNonCommentLine(sourceLines, lineIndex+1)
76
76
-
77
77
-
if nextLineNumber > 0 {
78
78
-
nextInformation := lineInformationMap[nextLineNumber]
79
79
-
80
80
-
if nextInformation != nil {
81
81
-
nextIsTopLevel := nextInformation.isTopLevel
82
82
-
nextIsScoped := nextInformation.isScoped
83
83
-
84
84
-
if nextIsTopLevel && previousWasTopLevel && nextInformation.statementType != previousStatementType {
85
85
-
needsBlankLine = true
86
86
-
} else if nextIsScoped || previousWasScoped {
87
87
-
needsBlankLine = true
88
88
-
} else if nextInformation.statementType != "" && previousStatementType != "" && nextInformation.statementType != previousStatementType {
89
89
-
needsBlankLine = true
90
90
-
}
91
91
-
}
92
92
-
}
93
93
-
}
94
94
-
}
95
95
-
96
96
-
if needsBlankLine {
97
97
-
resultLines = append(resultLines, "")
98
98
-
}
99
99
-
100
100
-
resultLines = append(resultLines, currentLine)
101
101
-
previousWasOpenBrace = isOpeningBraceLine || isCaseLabelLine
102
102
-
previousWasComment = isCommentOnlyLine
103
103
-
104
104
-
if currentInformation != nil {
105
105
-
previousStatementType = currentInformation.statementType
106
106
-
previousWasTopLevel = currentInformation.isTopLevel
107
107
-
previousWasScoped = currentInformation.isScoped
108
108
-
} else if currentStatementType != "" {
109
109
-
previousStatementType = currentStatementType
110
110
-
previousWasTopLevel = false
111
111
-
previousWasScoped = false
112
112
-
}
113
113
-
}
114
114
-
115
115
-
outputString := strings.Join(resultLines, "\n")
116
116
-
117
117
-
if !strings.HasSuffix(outputString, "\n") {
118
118
-
outputString += "\n"
119
119
-
}
120
120
-
121
121
-
return []byte(outputString)
122
122
-
}
123
123
-
124
124
-
func (f *Formatter) findNextNonCommentLine(sourceLines []string, startLineIndex int) int {
125
125
-
for lineIndex := startLineIndex; lineIndex < len(sourceLines); lineIndex++ {
126
126
-
trimmedLine := strings.TrimSpace(sourceLines[lineIndex])
127
127
-
128
128
-
if trimmedLine == "" {
129
129
-
continue
130
130
-
}
131
131
-
132
132
-
if isCommentOnly(sourceLines[lineIndex]) {
133
133
-
continue
134
134
-
}
135
135
-
136
136
-
return lineIndex + 1
137
137
-
}
138
138
-
139
139
-
return 0
140
140
-
}