Initial commit

This commit is contained in:
NinjaPug
2025-06-10 16:10:59 -04:00
commit edd1b1dbb1
624 changed files with 1174453 additions and 0 deletions

121
out/analyzer/CSSAnalyzer.js Normal file
View File

@@ -0,0 +1,121 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CSSAnalyzer = void 0;
class CSSAnalyzer {
extractSelectors(document) {
const selectors = new Map();
const text = document.getText();
// Parse CSS/SCSS using regex-based approach
this.parseStylesheet(text, selectors);
return selectors;
}
parseStylesheet(text, selectors) {
const lines = text.split('\n');
let inComment = false;
let inRule = false;
let braceCount = 0;
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
// Handle multi-line comments
if (inComment) {
const commentEnd = line.indexOf('*/');
if (commentEnd !== -1) {
inComment = false;
line = line.substring(commentEnd + 2);
}
else {
continue;
}
}
// Remove single-line comments
const commentStart = line.indexOf('//');
if (commentStart !== -1) {
line = line.substring(0, commentStart);
}
// Handle multi-line comment start
const multiCommentStart = line.indexOf('/*');
if (multiCommentStart !== -1) {
const multiCommentEnd = line.indexOf('*/', multiCommentStart);
if (multiCommentEnd !== -1) {
line = line.substring(0, multiCommentStart) + line.substring(multiCommentEnd + 2);
}
else {
inComment = true;
line = line.substring(0, multiCommentStart);
}
}
// Count braces to track nesting
const openBraces = (line.match(/\{/g) || []).length;
const closeBraces = (line.match(/\}/g) || []).length;
// If we're not in a rule and line contains a selector pattern
if (!inRule && braceCount === 0) {
const selectorMatch = this.extractSelectorFromLine(line, i);
if (selectorMatch) {
selectors.set(selectorMatch.selector, {
line: i,
character: selectorMatch.character,
length: selectorMatch.length
});
}
}
braceCount += openBraces - closeBraces;
inRule = braceCount > 0;
}
}
extractSelectorFromLine(line, lineNumber) {
// Remove leading/trailing whitespace
const trimmed = line.trim();
// Skip empty lines, variables, imports, mixins, etc.
if (!trimmed ||
trimmed.startsWith('$') ||
trimmed.startsWith('@') ||
trimmed.startsWith('//') ||
trimmed.startsWith('/*') ||
!trimmed.includes('{')) {
return null;
}
// Extract selector part (everything before the opening brace)
const braceIndex = trimmed.indexOf('{');
if (braceIndex === -1) {
return null;
}
const selectorPart = trimmed.substring(0, braceIndex).trim();
// Validate that this looks like a CSS selector
if (this.isValidSelector(selectorPart)) {
const character = line.indexOf(selectorPart);
return {
selector: selectorPart,
character: character >= 0 ? character : 0,
length: selectorPart.length
};
}
return null;
}
isValidSelector(selector) {
// Skip SCSS control structures and mixins
if (selector.startsWith('@') ||
selector.includes('@if') ||
selector.includes('@for') ||
selector.includes('@while') ||
selector.includes('@each') ||
selector.includes('@mixin') ||
selector.includes('@include')) {
return false;
}
// Basic CSS selector patterns
const selectorPatterns = [
/^[.#]?[a-zA-Z_-][a-zA-Z0-9_-]*/,
/^::[a-zA-Z-]+/,
/^:[a-zA-Z-]+/,
/^\[.*\]/,
/^[*]/, // Universal selector
];
// Check if selector matches any valid pattern
return selectorPatterns.some(pattern => pattern.test(selector.trim())) ||
selector.includes('.') ||
selector.includes('#') ||
selector.includes(':');
}
}
exports.CSSAnalyzer = CSSAnalyzer;
//# sourceMappingURL=CSSAnalyzer.js.map