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
133 changes: 132 additions & 1 deletion src/core/file/fileManipulate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,137 @@ class CppManipulator extends BaseManipulator {
}
}

enum GoParserState {
Normal = 0,
InLineComment = 1,
InBlockComment = 2,
InDoubleQuoteString = 3,
InRawString = 4,
InRuneLiteral = 5,
}

class GoManipulator extends BaseManipulator {
removeComments(content: string): string {
if (!content) return '';

let state: GoParserState = GoParserState.Normal;
let result = '';
let i = 0;
let hasNonWhitespaceOnLine = false; // Track if line has non-whitespace content

while (i < content.length) {
const char = content[i];
const nextChar = i + 1 < content.length ? content[i + 1] : null;

switch (state) {
case GoParserState.Normal:
if (char === '/' && nextChar === '/') {
// Go directive handling
if (!hasNonWhitespaceOnLine) {
if (content.startsWith('//go:', i)) {
// Preserve //go: directives
const lineEnd = content.indexOf('\n', i);
if (lineEnd === -1) {
result += content.substring(i);
i = content.length;
} else {
result += content.substring(i, lineEnd + 1);
i = lineEnd + 1;
hasNonWhitespaceOnLine = false;
}
continue;
}
}
state = GoParserState.InLineComment;
i += 2; // skip '//'
continue;
}
if (char === '/' && nextChar === '*') {
state = GoParserState.InBlockComment;
i += 2; // skip '/*'
continue;
}
result += char;
if (char !== ' ' && char !== '\t' && char !== '\n') {
hasNonWhitespaceOnLine = true;
}
if (char === '"') {
state = GoParserState.InDoubleQuoteString;
} else if (char === '`') {
state = GoParserState.InRawString;
} else if (char === "'") {
state = GoParserState.InRuneLiteral;
}
break;

case GoParserState.InLineComment:
// Skip text within line comments until newline
if (char === '\n') {
result += char;
state = GoParserState.Normal;
hasNonWhitespaceOnLine = false;
}
// Skip all other characters
break;

case GoParserState.InBlockComment:
// Go block comments do not nest - first */ closes the comment
if (char === '*' && nextChar === '/') {
state = GoParserState.Normal;
i += 2; // skip '*/'
continue;
}
if (char === '\n') {
// Preserve newlines in block comments to maintain line structure
result += char;
hasNonWhitespaceOnLine = false;
}
// Skip all other characters within block comments
break;

case GoParserState.InDoubleQuoteString:
result += char;
if (char === '\\' && nextChar !== null) {
// Handle escape sequences
result += nextChar;
i += 2;
continue;
}
if (char === '"') {
state = GoParserState.Normal;
}
break;

case GoParserState.InRawString:
result += char;
if (char === '`') {
state = GoParserState.Normal;
}
break;

case GoParserState.InRuneLiteral:
result += char;
if (char === '\\' && nextChar !== null) {
// Handle escape sequences
result += nextChar;
i += 2;
continue;
}
if (char === "'") {
state = GoParserState.Normal;
}
break;
}

if (char === '\n') {
hasNonWhitespaceOnLine = false;
}
i++;
}
return rtrimLines(result);
}
}

class PythonManipulator extends BaseManipulator {
removeDocStrings(content: string): string {
if (!content) return '';
Expand Down Expand Up @@ -197,7 +328,7 @@ const manipulators: Record<string, FileManipulator> = {
'.cs': new StripCommentsManipulator('csharp'),
'.css': new StripCommentsManipulator('css'),
'.dart': new StripCommentsManipulator('c'),
'.go': new StripCommentsManipulator('c'),
'.go': new GoManipulator(),
'.html': new StripCommentsManipulator('html'),
'.java': new StripCommentsManipulator('java'),
'.js': new StripCommentsManipulator('javascript'),
Expand Down
74 changes: 74 additions & 0 deletions tests/core/file/fileManipulate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,80 @@ describe('fileManipulate', () => {
fmt.Println("Hello")
}
`,
},
{
name: 'Go directives preservation',
ext: '.go',
input: `//go:build linux
//go:generate something

package main

import "fmt"

func main() {
// Regular comment
s1 := "String with // not a comment"
s2 := \`raw string with
// this is not a comment
/* neither is this */\`

r := '/' // rune literal

/*
Multi-line comment
*/

fmt.Println("Hello") // end of line comment
}`,
expected: `//go:build linux
//go:generate something

package main

import "fmt"

func main() {

s1 := "String with // not a comment"
s2 := \`raw string with
// this is not a comment
/* neither is this */\`

r := '/'





fmt.Println("Hello")
}`,
},
{
name: 'Go mixed directives and comments',
ext: '.go',
input: `//go:build linux
// This is a comment, not a directive
//go:generate stringer -type=Color
// Another comment
package main`,
expected: `//go:build linux

//go:generate stringer -type=Color

package main`,
},
{
name: 'Go string literals with comments',
ext: '.go',
input: `s := "This is a string with \\"escaped\\" quotes // not a comment"
// This is a comment
r1 := '\\'' // Escaped single quote
r2 := '\\\\' // Backslash`,
expected: `s := "This is a string with \\"escaped\\" quotes // not a comment"

r1 := '\\''
r2 := '\\\\'`,
},
{
name: 'Kotlin comment removal',
Expand Down
Loading