-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3ad3cfa
commit 3aea579
Showing
3 changed files
with
127 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
function replaceWithWhitespace(input: string, pattern: RegExp): string { | ||
return input.replace(pattern, match => ' '.repeat(match.length)); | ||
} | ||
export function isBalanced(sourceCode = ''): boolean { | ||
function preprocess(code: string): string { | ||
const patterns = [ | ||
// single-line comments | ||
/\/\/.*$/gm, | ||
// multi-line comments | ||
/\/\*[\s\S]*?\*\//g, | ||
// string literals (both single and double quotes), handling escaped quotes | ||
/'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, | ||
// regex literals, handling escaped forward slashes | ||
/\/(?:[^\/\\]|\\.)*\/[gimsuy]*/g, | ||
] | ||
let result = code; | ||
for (const pattern of patterns) { | ||
result = replaceWithWhitespace(result, pattern); | ||
} | ||
return result; | ||
} | ||
|
||
// Step 2: Check for balanced brackets | ||
function checkBalance(code: string): boolean { | ||
const bracketPairs = { | ||
")": "(", | ||
"]": "[", | ||
"}": "{" | ||
}; | ||
const stack: string[] = []; | ||
const bracketRegex = /[()[{}\]]/g; | ||
|
||
let match: RegExpExecArray | null; | ||
// biome-ignore lint/suspicious/noAssignInExpressions: <explanation> | ||
while ((match = bracketRegex.exec(code)) !== null) { | ||
const char = match[0]; | ||
if ("([{".includes(char)) { | ||
stack.push(char); | ||
} else if (stack.length === 0 || stack.pop() !== bracketPairs[char]) { | ||
return false; | ||
} | ||
} | ||
|
||
return stack.length === 0; | ||
} | ||
|
||
return checkBalance(preprocess(sourceCode)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { describe, test, expect } from "vitest"; | ||
import { isBalanced } from '../src/balancer'; | ||
|
||
describe('isBalanced', () => { | ||
test('Empty string', () => { | ||
expect(isBalanced('')).toBe(true); | ||
}); | ||
|
||
test('Balanced brackets', () => { | ||
expect(isBalanced('()')).toBe(true); | ||
expect(isBalanced('()[]{}')).toBe(true); | ||
expect(isBalanced('([{}])')).toBe(true); | ||
}); | ||
|
||
test('Unbalanced brackets', () => { | ||
expect(isBalanced('(')).toBe(false); | ||
expect(isBalanced(')')).toBe(false); | ||
expect(isBalanced('(]')).toBe(false); | ||
expect(isBalanced('([)]')).toBe(false); | ||
}); | ||
|
||
test('Brackets in strings', () => { | ||
expect(isBalanced('"()"')).toBe(true); | ||
expect(isBalanced("'()'")).toBe(true); | ||
expect(isBalanced('const str = "(["')).toBe(true); | ||
}); | ||
|
||
test('Escaped characters in strings', () => { | ||
expect(isBalanced('"\\""')).toBe(true); | ||
expect(isBalanced("'\\''")).toBe(true); | ||
expect(isBalanced('const str = "(\\"["')).toBe(true); | ||
}); | ||
|
||
test('Comments', () => { | ||
expect(isBalanced('// )')).toBe(true); | ||
expect(isBalanced('/* } */')).toBe(true); | ||
expect(isBalanced('// (\nconst x = 1;')).toBe(true); | ||
}); | ||
|
||
test('Regular expressions', () => { | ||
expect(isBalanced('/\\(/')).toBe(true); | ||
expect(isBalanced('const regex = /\\[/g')).toBe(true); | ||
}); | ||
|
||
test('Complex code snippets', () => { | ||
expect(isBalanced(` | ||
function test() { | ||
const str = "({[]})"; | ||
// Comment (]) | ||
return str.match(/\\(/g); | ||
} | ||
`)).toBe(true); | ||
|
||
expect(isBalanced(` | ||
const obj = { | ||
key: '(]', | ||
nested: { | ||
array: [1, 2, 3] | ||
} | ||
}; | ||
/* Multi-line | ||
comment } */ | ||
console.log(obj); | ||
`)).toBe(true); | ||
}); | ||
|
||
test('Unbalanced complex code', () => { | ||
expect(isBalanced(` | ||
function broken( { | ||
const str = "(unmatched"; | ||
return str; | ||
} | ||
`)).toBe(false); | ||
}); | ||
}); |