Skip to content

Commit 787cfca

Browse files
committed
Extend file compaction support to include Ruby, CSS, and SQL languages
1 parent 6017541 commit 787cfca

13 files changed

Lines changed: 431 additions & 5 deletions

File tree

‎packages/vscode/src/context/utils/compact-file/compact-file.spec.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,19 @@ describe('compact_file', () => {
8181
const { input, expected } = load_test_case('python', '.')
8282
expect(compact_file(input, '.py')).toBe(expected)
8383
})
84+
85+
it('should strip ruby method bodies', () => {
86+
const { input, expected } = load_test_case('ruby', '.')
87+
expect(compact_file(input, '.rb')).toBe(expected)
88+
})
89+
90+
it('should strip css bodies', () => {
91+
const { input, expected } = load_test_case('css', '.')
92+
expect(compact_file(input, '.css')).toBe(expected)
93+
})
94+
95+
it('should strip sql comments', () => {
96+
const { input, expected } = load_test_case('sql', '.')
97+
expect(compact_file(input, '.sql')).toBe(expected)
98+
})
8499
})
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
import { compact_c_style } from './languages/c-style'
2+
import { compact_css } from './languages/css'
23
import { compact_python } from './languages/python'
4+
import { compact_ruby } from './languages/ruby'
5+
import { compact_sql } from './languages/sql'
36

47
export const compact_file = (content: string, extension: string): string => {
58
if (extension == '.py') {
69
return compact_python(content)
710
}
11+
if (extension == '.rb') {
12+
return compact_ruby(content)
13+
}
14+
if (['.css', '.scss', '.less'].includes(extension)) {
15+
return compact_css(content)
16+
}
17+
if (extension == '.sql') {
18+
return compact_sql(content)
19+
}
820

921
return compact_c_style(content, true)
1022
}

‎packages/vscode/src/context/utils/compact-file/languages/c-style.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const compact_c_style = (
2121

2222
// Handle Block Comments
2323
if (is_in_block_comment) {
24-
if (char === '*' && next_char === '/') {
24+
if (char == '*' && next_char == '/') {
2525
is_in_block_comment = false
2626
i += 2
2727
} else {
@@ -53,7 +53,7 @@ export const compact_c_style = (
5353
}
5454

5555
// Start of String
56-
if (char === '"' || char === "'" || char === '`') {
56+
if (char == '"' || char === "'" || char == '`') {
5757
is_in_string = char
5858
if (skip_body_depth === 0) {
5959
processed_line += char
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
export const compact_css = (content: string): string => {
2+
// Split by newline to process line by line, handling both LF and CRLF
3+
const lines = content.split(/\r?\n/)
4+
const result: string[] = []
5+
let is_in_block_comment = false
6+
let skip_body_depth = 0
7+
// Buffer to track context for stripping bodies (e.g. "@media ... ")
8+
let last_code_buffer = ''
9+
10+
for (const line of lines) {
11+
let processed_line = ''
12+
let i = 0
13+
let is_in_string: false | '"' | "'" = false
14+
15+
while (i < line.length) {
16+
const char = line[i]
17+
const next_char = line[i + 1]
18+
19+
// Handle Block Comments
20+
if (is_in_block_comment) {
21+
if (char == '*' && next_char == '/') {
22+
is_in_block_comment = false
23+
i += 2
24+
} else {
25+
i++
26+
}
27+
continue
28+
}
29+
30+
// Handle Strings (ignore comments inside strings)
31+
if (is_in_string) {
32+
if (char == '\\') {
33+
// Handle escaped characters inside string
34+
if (skip_body_depth === 0) {
35+
processed_line += char + (next_char || '')
36+
}
37+
last_code_buffer += char + (next_char || '')
38+
i += 2
39+
continue
40+
}
41+
if (char === is_in_string) {
42+
is_in_string = false
43+
}
44+
if (skip_body_depth === 0) {
45+
processed_line += char
46+
}
47+
last_code_buffer += char
48+
i++
49+
continue
50+
}
51+
52+
// Start of String
53+
if (char == '"' || char === "'") {
54+
is_in_string = char
55+
if (skip_body_depth === 0) {
56+
processed_line += char
57+
}
58+
last_code_buffer += char
59+
i++
60+
continue
61+
}
62+
63+
// Start of Line Comment (Support // for SCSS/LESS, though not standard CSS)
64+
if (char == '/' && next_char == '/') {
65+
break // Ignore the rest of the line
66+
}
67+
68+
// Start of Block Comment
69+
if (char == '/' && next_char == '*') {
70+
is_in_block_comment = true
71+
i += 2
72+
continue
73+
}
74+
75+
// Handle Body Stripping
76+
if (char == '{') {
77+
if (skip_body_depth > 0) {
78+
// Already skipping, just deepen the level
79+
skip_body_depth++
80+
last_code_buffer += char
81+
i++
82+
continue
83+
} else {
84+
// Check if we should preserve this block (at-rules like @media)
85+
const is_keeper =
86+
/(@media|@supports|@keyframes|@layer|@container)\b/.test(
87+
last_code_buffer
88+
)
89+
90+
if (!is_keeper) {
91+
// Start skipping
92+
skip_body_depth = 1
93+
processed_line += '{}'
94+
last_code_buffer += '{}'
95+
i++
96+
continue
97+
} else {
98+
// Keeper: reset buffer
99+
last_code_buffer = ''
100+
}
101+
}
102+
} else if (char == '}') {
103+
if (skip_body_depth > 0) {
104+
skip_body_depth--
105+
last_code_buffer += char
106+
i++
107+
continue
108+
}
109+
}
110+
111+
// Regular character
112+
if (skip_body_depth == 0) {
113+
processed_line += char
114+
}
115+
last_code_buffer += char
116+
i++
117+
}
118+
119+
// We trim the line to actually "compact" the file.
120+
// If a line contained only comments, it becomes empty and is skipped.
121+
const trimmed = processed_line.trim()
122+
if (trimmed) {
123+
result.push(trimmed)
124+
}
125+
126+
// Add a space to buffer for newline
127+
last_code_buffer += ' '
128+
// Limit buffer size
129+
if (last_code_buffer.length > 200) {
130+
last_code_buffer = last_code_buffer.slice(-200)
131+
}
132+
}
133+
134+
return result.length > 0 ? result.join('\n') + '\n' : ''
135+
}

‎packages/vscode/src/context/utils/compact-file/languages/python.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const compact_python = (content: string): string => {
2525
const char = line[i]
2626

2727
if (in_string) {
28-
if (char === '\\') {
28+
if (char == '\\') {
2929
processed_line += char + (line[i + 1] || '')
3030
i += 2
3131
continue
@@ -45,15 +45,15 @@ export const compact_python = (content: string): string => {
4545
i++
4646
} else {
4747
// Start of String
48-
if (char === '"' || char === "'") {
48+
if (char == '"' || char === "'") {
4949
const is_triple = line.substring(i, i + 3) === char.repeat(3)
5050
in_string = is_triple ? char.repeat(3) : char
5151
processed_line += in_string
5252
i += in_string.length
5353
continue
5454
}
5555
// Start of Comment
56-
if (char === '#') {
56+
if (char == '#') {
5757
break // Ignore rest of line
5858
}
5959
processed_line += char
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
export const compact_ruby = (content: string): string => {
2+
const lines = content.split(/\r?\n/)
3+
const result: string[] = []
4+
let skip_indent_threshold = -1
5+
6+
for (const line of lines) {
7+
// 1. Calculate Indentation
8+
const match = line.match(/^\s*/)
9+
const current_indent = match ? match[0].length : 0
10+
11+
// 2. Handle Skipping (Body Stripping)
12+
if (skip_indent_threshold !== -1) {
13+
if (current_indent > skip_indent_threshold) {
14+
continue
15+
}
16+
skip_indent_threshold = -1
17+
}
18+
19+
// 3. Strip Comments (simplified char loop to handle strings)
20+
let processed_line = ''
21+
let in_string: string | false = false
22+
let i = 0
23+
24+
while (i < line.length) {
25+
const char = line[i]
26+
27+
if (in_string) {
28+
if (char == '\\') {
29+
processed_line += char + (line[i + 1] || '')
30+
i += 2
31+
continue
32+
}
33+
// Check for end of string
34+
if (char === in_string) {
35+
processed_line += in_string
36+
in_string = false
37+
i++
38+
continue
39+
}
40+
processed_line += char
41+
i++
42+
} else {
43+
// Start of String
44+
if (char == '"' || char === "'") {
45+
in_string = char
46+
processed_line += char
47+
i++
48+
continue
49+
}
50+
// Start of Comment
51+
if (char == '#') {
52+
break // Ignore rest of line
53+
}
54+
processed_line += char
55+
i++
56+
}
57+
}
58+
59+
const trimmed = processed_line.trim()
60+
if (!trimmed) continue
61+
62+
// 4. Check for Block Start to Strip (def)
63+
// We only strip 'def' methods that span multiple lines (don't end with 'end')
64+
if (/^def\b/.test(trimmed) && !/\bend\s*$/.test(trimmed)) {
65+
result.push(processed_line)
66+
result.push(line.substring(0, current_indent) + ' ' + '# ...')
67+
skip_indent_threshold = current_indent
68+
continue
69+
}
70+
71+
result.push(processed_line)
72+
}
73+
74+
return result.join('\n') + '\n'
75+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
export const compact_sql = (content: string): string => {
2+
const lines = content.split(/\r?\n/)
3+
const result: string[] = []
4+
let is_in_block_comment = false
5+
6+
for (const line of lines) {
7+
let processed_line = ''
8+
let i = 0
9+
let is_in_string: false | '"' | "'" = false
10+
11+
while (i < line.length) {
12+
const char = line[i]
13+
const next_char = line[i + 1]
14+
15+
// Handle Block Comments
16+
if (is_in_block_comment) {
17+
if (char == '*' && next_char == '/') {
18+
is_in_block_comment = false
19+
i += 2
20+
} else {
21+
i++
22+
}
23+
continue
24+
}
25+
26+
// Handle Strings
27+
if (is_in_string) {
28+
// specific SQL escape: double quote to escape quote (e.g. 'Don''t')
29+
if (char === is_in_string && next_char === is_in_string) {
30+
processed_line += char + next_char
31+
i += 2
32+
continue
33+
}
34+
// Backslash escape (common dialect support)
35+
if (char == '\\') {
36+
processed_line += char + (next_char || '')
37+
i += 2
38+
continue
39+
}
40+
if (char === is_in_string) {
41+
is_in_string = false
42+
}
43+
processed_line += char
44+
i++
45+
continue
46+
}
47+
48+
// Start of String
49+
if (char == '"' || char === "'") {
50+
is_in_string = char
51+
processed_line += char
52+
i++
53+
continue
54+
}
55+
56+
// Start of Line Comment
57+
if (char == '-' && next_char == '-') {
58+
break // Ignore the rest of the line
59+
}
60+
61+
// Start of Block Comment
62+
if (char == '/' && next_char == '*') {
63+
is_in_block_comment = true
64+
i += 2
65+
continue
66+
}
67+
68+
// Regular character
69+
processed_line += char
70+
i++
71+
}
72+
73+
const trimmed = processed_line.trim()
74+
if (trimmed) {
75+
result.push(trimmed)
76+
}
77+
}
78+
79+
return result.length > 0 ? result.join('\n') + '\n' : ''
80+
}

0 commit comments

Comments
 (0)