Something went wrong. Try again.
🚀 Grammar-Aware Code Formatter: Structure through separation (supports Go, JavaScript, TypeScript, JSX, and TSX)
go formatter code-formatter javascript typescript jsx tsx
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157package engine
import "strings"
type CommentMode int
const ( CommentsFollow CommentMode = iota CommentsPrecede CommentsStandalone)
type Engine struct { CommentMode CommentMode GroupSingleLineScopes bool}
func (e *Engine) format(events []LineEvent, resultBuilder *strings.Builder) { hasWrittenContent := false previousWasOpenBrace := false previousStatementType := "" previousWasComment := false previousWasTopLevel := false previousWasScoped := false previousWasSingleLineScope := false
for eventIndex, event := range events { if event.InRawString { if hasWrittenContent { resultBuilder.WriteByte('\n') }
resultBuilder.WriteString(event.Content)
hasWrittenContent = true
continue }
if event.IsBlank { continue }
currentStatementType := event.StatementType
if event.IsPackageDecl { currentStatementType = "package" }
needsBlankLine := false currentIsTopLevel := event.HasASTInfo && event.IsTopLevel currentIsScoped := event.HasASTInfo && event.IsScoped currentIsSingleLineScope := currentIsScoped && !event.IsOpeningBrace && !event.IsClosingBrace
if hasWrittenContent && !previousWasOpenBrace && !event.IsClosingBrace && !event.IsCaseLabel && !event.IsContinuation { if currentIsTopLevel && previousWasTopLevel && currentStatementType != previousStatementType { if e.CommentMode != CommentsFollow || !previousWasComment { needsBlankLine = true } } else if event.HasASTInfo && (currentIsScoped || previousWasScoped) { if e.GroupSingleLineScopes && currentIsSingleLineScope && previousWasSingleLineScope && currentStatementType == previousStatementType { needsBlankLine = false } else if e.CommentMode != CommentsFollow || !previousWasComment { needsBlankLine = true } } else if currentStatementType != "" && previousStatementType != "" && currentStatementType != previousStatementType { if e.CommentMode != CommentsFollow || !previousWasComment { needsBlankLine = true } }
if e.CommentMode == CommentsFollow && event.IsCommentOnly && !previousWasComment { nextIndex := e.findNextNonComment(events, eventIndex+1)
if nextIndex >= 0 { nextNonCommentEvent := events[nextIndex]
if nextNonCommentEvent.HasASTInfo { nextIsTopLevel := nextNonCommentEvent.IsTopLevel nextIsScoped := nextNonCommentEvent.IsScoped
if nextIsTopLevel && previousWasTopLevel && nextNonCommentEvent.StatementType != previousStatementType { needsBlankLine = true } else if nextIsScoped || previousWasScoped { needsBlankLine = true } else if nextNonCommentEvent.StatementType != "" && previousStatementType != "" && nextNonCommentEvent.StatementType != previousStatementType { needsBlankLine = true } } } } }
if needsBlankLine { resultBuilder.WriteByte('\n') }
if hasWrittenContent { resultBuilder.WriteByte('\n') }
resultBuilder.WriteString(event.Content)
hasWrittenContent = true previousWasOpenBrace = event.IsOpeningBrace || event.IsCaseLabel previousWasComment = event.IsCommentOnly
if event.HasASTInfo { previousStatementType = event.StatementType previousWasTopLevel = event.IsTopLevel previousWasScoped = event.IsScoped previousWasSingleLineScope = currentIsSingleLineScope } else if currentStatementType != "" { previousStatementType = currentStatementType previousWasTopLevel = false previousWasScoped = false previousWasSingleLineScope = false } }
resultBuilder.WriteByte('\n')}
func (e *Engine) FormatToString(events []LineEvent) string { var resultBuilder strings.Builder
resultBuilder.Grow(len(events) * 40) e.format(events, &resultBuilder)
return resultBuilder.String()}
func (e *Engine) FormatToBytes(events []LineEvent) []byte { var resultBuilder strings.Builder
resultBuilder.Grow(len(events) * 40) e.format(events, &resultBuilder)
return []byte(resultBuilder.String())}
func (e *Engine) findNextNonComment(events []LineEvent, startIndex int) int { for eventIndex := startIndex; eventIndex < len(events); eventIndex++ { if events[eventIndex].IsBlank { continue }
if events[eventIndex].IsCommentOnly { continue }
return eventIndex }
return -1}