ctrlshiftleft
Version:
AI-powered toolkit for embedding QA and security testing into development workflows
103 lines • 3.81 kB
JavaScript
;
/**
* Utilities for calculating and displaying diffs between files
* Used for security change analysis in the watch command
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.diff = diff;
exports.isSecuritySensitiveChange = isSecuritySensitiveChange;
exports.highlightSecurityChanges = highlightSecurityChanges;
/**
* Compute diff between two strings
* @param oldStr Previous string content
* @param newStr New string content
* @returns Array of diff changes
*/
function diff(oldStr, newStr) {
if (oldStr === newStr) {
return [{ value: newStr }];
}
// Convert strings to arrays of lines
const oldLines = oldStr.split('\n');
const newLines = newStr.split('\n');
const result = [];
// Myers diff algorithm simplified for line-by-line comparison
const MAX_EDIT_LENGTH = Math.max(oldLines.length, newLines.length);
// Identify unchanged lines
let i = 0;
while (i < oldLines.length && i < newLines.length && oldLines[i] === newLines[i]) {
i++;
}
if (i > 0) {
// Add context of unchanged lines at the beginning (limited to a few lines)
const contextLines = oldLines.slice(Math.max(0, i - 3), i);
if (contextLines.length > 0) {
result.push({ value: contextLines.join('\n') });
}
}
// Find trailing same lines
let j = 0;
while (oldLines.length - j - 1 >= 0 &&
newLines.length - j - 1 >= 0 &&
oldLines[oldLines.length - j - 1] === newLines[newLines.length - j - 1] &&
oldLines.length - j - 1 > i &&
newLines.length - j - 1 > i) {
j++;
}
// Add removed lines
if (i < oldLines.length - j) {
const removedLines = oldLines.slice(i, oldLines.length - j);
result.push({ value: removedLines.join('\n'), removed: true });
}
// Add added lines
if (i < newLines.length - j) {
const addedLines = newLines.slice(i, newLines.length - j);
result.push({ value: addedLines.join('\n'), added: true });
}
// Add unchanged lines at the end for context
if (j > 0) {
const contextLines = oldLines.slice(oldLines.length - Math.min(j, 3), oldLines.length);
if (contextLines.length > 0) {
result.push({ value: contextLines.join('\n') });
}
}
return result;
}
/**
* Check if a line contains security-sensitive changes
* @param line Line of code to check
* @returns Whether line contains security-sensitive keywords
*/
function isSecuritySensitiveChange(line) {
const securityKeywords = [
'auth', 'password', 'token', 'secret', 'key', 'credential',
'encrypt', 'decrypt', 'hash', 'salt', 'security', 'permission',
'XSS', 'CSRF', 'SQL', 'injection', 'sanitize', 'validate',
'CORS', 'header', 'certificate', 'SSL', 'TLS', 'HTTPS'
];
const lowerLine = line.toLowerCase();
return securityKeywords.some(keyword => lowerLine.includes(keyword.toLowerCase()));
}
/**
* Highlight security-sensitive changes in diff output
* @param changes Diff changes to analyze
* @returns Formatted string with highlighted security changes
*/
function highlightSecurityChanges(changes) {
let highlightedOutput = '';
for (const change of changes) {
const lines = change.value.split('\n');
for (const line of lines) {
const isSecurityLine = isSecuritySensitiveChange(line);
const indicator = change.added ? '+' : change.removed ? '-' : ' ';
if (isSecurityLine) {
highlightedOutput += `🔒 ${indicator} ${line}\n`;
}
else {
highlightedOutput += `${indicator} ${line}\n`;
}
}
}
return highlightedOutput;
}
//# sourceMappingURL=diffUtils.js.map