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

View File

@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AngularComponentAnalyzer = void 0;
const CSSAnalyzer_1 = require("./CSSAnalyzer");
const HTMLAnalyzer_1 = require("./HTMLAnalyzer");
const TypeScriptAnalyzer_1 = require("./TypeScriptAnalyzer");
const FileResolver_1 = require("../utils/FileResolver");
const UnusedStyleFinder_1 = require("../utils/UnusedStyleFinder");
class AngularComponentAnalyzer {
constructor() {
this.cssAnalyzer = new CSSAnalyzer_1.CSSAnalyzer();
this.htmlAnalyzer = new HTMLAnalyzer_1.HTMLAnalyzer();
this.tsAnalyzer = new TypeScriptAnalyzer_1.TypeScriptAnalyzer();
this.fileResolver = new FileResolver_1.FileResolver();
this.unusedStyleFinder = new UnusedStyleFinder_1.UnusedStyleFinder();
}
async analyzeComponent(componentFiles) {
if (!componentFiles.styles) {
return [];
}
const cssSelectors = this.cssAnalyzer.extractSelectors(componentFiles.styles);
const htmlUsedSelectors = componentFiles.html ?
this.htmlAnalyzer.extractUsedSelectors(componentFiles.html) : new Set();
const tsUsedSelectors = componentFiles.typescript ?
this.tsAnalyzer.extractDynamicSelectors(componentFiles.typescript) : new Set();
const allUsedSelectors = new Set([...htmlUsedSelectors, ...tsUsedSelectors]);
return this.unusedStyleFinder.findUnusedStyles(cssSelectors, allUsedSelectors, componentFiles.styles);
}
async getComponentFiles(document) {
return this.fileResolver.getComponentFiles(document);
}
}
exports.AngularComponentAnalyzer = AngularComponentAnalyzer;
//# sourceMappingURL=AngularComponentAnalyzer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"AngularComponentAnalyzer.js","sourceRoot":"","sources":["../../src/analyzer/AngularComponentAnalyzer.ts"],"names":[],"mappings":";;;AACA,+CAA4C;AAC5C,iDAA8C;AAC9C,6DAA0D;AAE1D,wDAAqD;AACrD,kEAA+D;AAE/D,MAAa,wBAAwB;IAArC;QACY,gBAAW,GAAG,IAAI,yBAAW,EAAE,CAAC;QAChC,iBAAY,GAAG,IAAI,2BAAY,EAAE,CAAC;QAClC,eAAU,GAAG,IAAI,uCAAkB,EAAE,CAAC;QACtC,iBAAY,GAAG,IAAI,2BAAY,EAAE,CAAC;QAClC,sBAAiB,GAAG,IAAI,qCAAiB,EAAE,CAAC;IAqBxD,CAAC;IAnBG,KAAK,CAAC,gBAAgB,CAAC,cAA8B;QACjD,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE;YACxB,OAAO,EAAE,CAAC;SACb;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAC9E,MAAM,iBAAiB,GAAgB,cAAc,CAAC,IAAI,CAAC,CAAC;YACxD,IAAI,CAAC,YAAY,CAAC,oBAAoB,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAU,CAAC;QACpF,MAAM,eAAe,GAAgB,cAAc,CAAC,UAAU,CAAC,CAAC;YAC5D,IAAI,CAAC,UAAU,CAAC,uBAAuB,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAU,CAAC;QAE3F,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,iBAAiB,EAAE,GAAG,eAAe,CAAC,CAAC,CAAC;QAErF,OAAO,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,YAAY,EAAE,gBAAgB,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC1G,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAA6B;QACjD,OAAO,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACzD,CAAC;CACJ;AA1BD,4DA0BC"}

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

View File

@@ -0,0 +1 @@
{"version":3,"file":"CSSAnalyzer.js","sourceRoot":"","sources":["../../src/analyzer/CSSAnalyzer.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HTMLAnalyzer = void 0;
class HTMLAnalyzer {
extractUsedSelectors(document) {
const usedSelectors = new Set();
const text = document.getText();
// Extract class attributes
const classMatches = text.match(/class\s*=\s*["']([^"']+)["']/g) || [];
classMatches.forEach(match => {
const classes = match.replace(/class\s*=\s*["']([^"']+)["']/, '$1').split(/\s+/);
classes.forEach(cls => cls.trim() && usedSelectors.add(cls.trim()));
});
// Extract id attributes
const idMatches = text.match(/id\s*=\s*["']([^"']+)["']/g) || [];
idMatches.forEach(match => {
const id = match.replace(/id\s*=\s*["']([^"']+)["']/, '$1').trim();
if (id)
usedSelectors.add(id);
});
// Extract Angular class bindings
const ngClassMatches = text.match(/\[class\.([^\]]+)\]/g) || [];
ngClassMatches.forEach(match => {
const className = match.replace(/\[class\.([^\]]+)\]/, '$1');
usedSelectors.add(className);
});
// Extract ngClass bindings
const ngClassObjectMatches = text.match(/\[ngClass\]\s*=\s*["']([^"']+)["']/g) || [];
ngClassObjectMatches.forEach(match => {
const expr = match.replace(/\[ngClass\]\s*=\s*["']([^"']+)["']/, '$1');
// This would need more sophisticated parsing for object expressions
const possibleClasses = expr.match(/['"`]([^'"`]+)['"`]/g) || [];
possibleClasses.forEach(cls => {
const className = cls.replace(/['"`]/g, '');
usedSelectors.add(className);
});
});
return usedSelectors;
}
}
exports.HTMLAnalyzer = HTMLAnalyzer;
//# sourceMappingURL=HTMLAnalyzer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"HTMLAnalyzer.js","sourceRoot":"","sources":["../../src/analyzer/HTMLAnalyzer.ts"],"names":[],"mappings":";;;AAEA,MAAa,YAAY;IACrB,oBAAoB,CAAC,QAA6B;QAC9C,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;QACxC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QAEhC,2BAA2B;QAC3B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,+BAA+B,CAAC,IAAI,EAAE,CAAC;QACvE,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACzB,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,8BAA8B,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACjF,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACxE,CAAC,CAAC,CAAC;QAEH,wBAAwB;QACxB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,4BAA4B,CAAC,IAAI,EAAE,CAAC;QACjE,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACtB,MAAM,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,2BAA2B,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACnE,IAAI,EAAE;gBAAE,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,iCAAiC;QACjC,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC;QAChE,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YAC3B,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC;YAC7D,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,2BAA2B;QAC3B,MAAM,oBAAoB,GAAG,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,IAAI,EAAE,CAAC;QACrF,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACjC,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,oCAAoC,EAAE,IAAI,CAAC,CAAC;YACvE,oEAAoE;YACpE,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC;YACjE,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;gBAC1B,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;gBAC5C,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,OAAO,aAAa,CAAC;IACzB,CAAC;CACJ;AAxCD,oCAwCC"}

View File

@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TypeScriptAnalyzer = void 0;
class TypeScriptAnalyzer {
extractDynamicSelectors(document) {
const dynamicSelectors = new Set();
const text = document.getText();
// Look for renderer.addClass, renderer.removeClass calls
const rendererMatches = text.match(/renderer\.(addClass|removeClass)\s*\(\s*[^,]+,\s*['"`]([^'"`]+)['"`]/g) || [];
rendererMatches.forEach(match => {
const className = match.replace(/.*['"`]([^'"`]+)['"`].*/, '$1');
dynamicSelectors.add(className);
});
// Look for element.classList operations
const classListMatches = text.match(/\.classList\.(add|remove|toggle)\s*\(\s*['"`]([^'"`]+)['"`]/g) || [];
classListMatches.forEach(match => {
const className = match.replace(/.*['"`]([^'"`]+)['"`].*/, '$1');
dynamicSelectors.add(className);
});
// Look for HostBinding decorators
const hostBindingMatches = text.match(/@HostBinding\s*\(\s*['"`]class\.([^'"`]+)['"`]/g) || [];
hostBindingMatches.forEach(match => {
const className = match.replace(/@HostBinding\s*\(\s*['"`]class\.([^'"`]+)['"`].*/, '$1');
dynamicSelectors.add(className);
});
// Look for string literals that might be class names
const stringLiteralMatches = text.match(/['"`][a-zA-Z_-][a-zA-Z0-9_-]*['"`]/g) || [];
stringLiteralMatches.forEach(match => {
const str = match.replace(/['"`]/g, '');
// Only consider strings that look like CSS class names
if (str.match(/^[a-zA-Z_-][a-zA-Z0-9_-]*$/) && str.length > 2) {
dynamicSelectors.add(str);
}
});
return dynamicSelectors;
}
}
exports.TypeScriptAnalyzer = TypeScriptAnalyzer;
//# sourceMappingURL=TypeScriptAnalyzer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"TypeScriptAnalyzer.js","sourceRoot":"","sources":["../../src/analyzer/TypeScriptAnalyzer.ts"],"names":[],"mappings":";;;AAEA,MAAa,kBAAkB;IAC3B,uBAAuB,CAAC,QAA6B;QACjD,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;QAC3C,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC;QAEhC,yDAAyD;QACzD,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,uEAAuE,CAAC,IAAI,EAAE,CAAC;QAClH,eAAe,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YAC5B,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,yBAAyB,EAAE,IAAI,CAAC,CAAC;YACjE,gBAAgB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,wCAAwC;QACxC,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,8DAA8D,CAAC,IAAI,EAAE,CAAC;QAC1G,gBAAgB,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YAC7B,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,yBAAyB,EAAE,IAAI,CAAC,CAAC;YACjE,gBAAgB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,kCAAkC;QAClC,MAAM,kBAAkB,GAAG,IAAI,CAAC,KAAK,CAAC,iDAAiD,CAAC,IAAI,EAAE,CAAC;QAC/F,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YAC/B,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,kDAAkD,EAAE,IAAI,CAAC,CAAC;YAC1F,gBAAgB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QAEH,qDAAqD;QACrD,MAAM,oBAAoB,GAAG,IAAI,CAAC,KAAK,CAAC,qCAAqC,CAAC,IAAI,EAAE,CAAC;QACrF,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACjC,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YACxC,uDAAuD;YACvD,IAAI,GAAG,CAAC,KAAK,CAAC,4BAA4B,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE;gBAC3D,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;aAC7B;QACL,CAAC,CAAC,CAAC;QAEH,OAAO,gBAAgB,CAAC;IAC5B,CAAC;CACJ;AAtCD,gDAsCC"}

66
out/extension.js Normal file
View File

@@ -0,0 +1,66 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.deactivate = exports.activate = void 0;
const vscode = __importStar(require("vscode"));
const AngularComponentAnalyzer_1 = require("./analyzer/AngularComponentAnalyzer");
const UnusedStylesProvider_1 = require("./providers/UnusedStylesProvider");
let analyzer;
let diagnosticCollection;
function activate(context) {
analyzer = new AngularComponentAnalyzer_1.AngularComponentAnalyzer();
diagnosticCollection = vscode.languages.createDiagnosticCollection('angular-unused-styles');
const provider = new UnusedStylesProvider_1.UnusedStylesProvider(analyzer, diagnosticCollection);
// Register command
const analyzeCommand = vscode.commands.registerCommand('angular-unused-styles.analyze', () => {
provider.analyzeCurrentWorkspace();
});
// Register document change handlers
const onDidChangeTextDocument = vscode.workspace.onDidChangeTextDocument(event => {
if (isAngularFile(event.document.fileName)) {
provider.analyzeDocument(event.document);
}
});
const onDidOpenTextDocument = vscode.workspace.onDidOpenTextDocument(document => {
if (isAngularFile(document.fileName)) {
provider.analyzeDocument(document);
}
});
context.subscriptions.push(analyzeCommand, onDidChangeTextDocument, onDidOpenTextDocument, diagnosticCollection);
}
exports.activate = activate;
function isAngularFile(fileName) {
return fileName.endsWith('.component.ts') ||
fileName.endsWith('.component.html') ||
fileName.endsWith('.component.scss') ||
fileName.endsWith('.component.css');
}
function deactivate() {
if (diagnosticCollection) {
diagnosticCollection.dispose();
}
}
exports.deactivate = deactivate;
//# sourceMappingURL=extension.js.map

1
out/extension.js.map Normal file
View File

@@ -0,0 +1 @@
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AACjC,kFAA+E;AAC/E,2EAAwE;AAExE,IAAI,QAAkC,CAAC;AACvC,IAAI,oBAAiD,CAAC;AAEtD,SAAgB,QAAQ,CAAC,OAAgC;IACrD,QAAQ,GAAG,IAAI,mDAAwB,EAAE,CAAC;IAC1C,oBAAoB,GAAG,MAAM,CAAC,SAAS,CAAC,0BAA0B,CAAC,uBAAuB,CAAC,CAAC;IAE5F,MAAM,QAAQ,GAAG,IAAI,2CAAoB,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;IAE1E,mBAAmB;IACnB,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACzF,QAAQ,CAAC,uBAAuB,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,oCAAoC;IACpC,MAAM,uBAAuB,GAAG,MAAM,CAAC,SAAS,CAAC,uBAAuB,CAAC,KAAK,CAAC,EAAE;QAC7E,IAAI,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;YACxC,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;SAC5C;IACL,CAAC,CAAC,CAAC;IAEH,MAAM,qBAAqB,GAAG,MAAM,CAAC,SAAS,CAAC,qBAAqB,CAAC,QAAQ,CAAC,EAAE;QAC5E,IAAI,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;YAClC,QAAQ,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;SACtC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,aAAa,CAAC,IAAI,CACtB,cAAc,EACd,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,CACvB,CAAC;AACN,CAAC;AA9BD,4BA8BC;AAED,SAAS,aAAa,CAAC,QAAgB;IACnC,OAAO,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC;QAClC,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QACpC,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QACpC,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAC/C,CAAC;AAED,SAAgB,UAAU;IACtB,IAAI,oBAAoB,EAAE;QACtB,oBAAoB,CAAC,OAAO,EAAE,CAAC;KAClC;AACL,CAAC;AAJD,gCAIC"}

View File

@@ -0,0 +1,71 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UnusedStylesProvider = void 0;
const vscode = __importStar(require("vscode"));
class UnusedStylesProvider {
constructor(analyzer, diagnosticCollection) {
this.analyzer = analyzer;
this.diagnosticCollection = diagnosticCollection;
}
async analyzeDocument(document) {
if (!this.isAngularStyleFile(document.fileName)) {
return;
}
const componentFiles = await this.analyzer.getComponentFiles(document);
const unusedStyles = await this.analyzer.analyzeComponent(componentFiles);
this.updateDiagnostics(document, unusedStyles);
}
async analyzeCurrentWorkspace() {
const workspaceFolders = vscode.workspace.workspaceFolders;
if (!workspaceFolders) {
return;
}
for (const folder of workspaceFolders) {
const pattern = new vscode.RelativePattern(folder, '**/*.component.{scss,css}');
const files = await vscode.workspace.findFiles(pattern);
for (const file of files) {
const document = await vscode.workspace.openTextDocument(file);
await this.analyzeDocument(document);
}
}
vscode.window.showInformationMessage('Angular unused styles analysis completed!');
}
updateDiagnostics(document, unusedStyles) {
const diagnostics = unusedStyles.map(unused => {
const range = new vscode.Range(unused.line, unused.character, unused.line, unused.character + unused.length);
const diagnostic = new vscode.Diagnostic(range, unused.reason, vscode.DiagnosticSeverity.Warning);
diagnostic.source = 'Angular Unused Styles';
diagnostic.code = 'unused-style';
return diagnostic;
});
this.diagnosticCollection.set(document.uri, diagnostics);
}
isAngularStyleFile(fileName) {
return fileName.endsWith('.component.scss') || fileName.endsWith('.component.css');
}
}
exports.UnusedStylesProvider = UnusedStylesProvider;
//# sourceMappingURL=UnusedStylesProvider.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"UnusedStylesProvider.js","sourceRoot":"","sources":["../../src/providers/UnusedStylesProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AAIjC,MAAa,oBAAoB;IAC7B,YACY,QAAkC,EAClC,oBAAiD;QADjD,aAAQ,GAAR,QAAQ,CAA0B;QAClC,yBAAoB,GAApB,oBAAoB,CAA6B;IAC1D,CAAC;IAEJ,KAAK,CAAC,eAAe,CAAC,QAA6B;QAC/C,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;YAC7C,OAAO;SACV;QAED,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QACvE,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC;QAE1E,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,uBAAuB;QACzB,MAAM,gBAAgB,GAAG,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC;QAC3D,IAAI,CAAC,gBAAgB,EAAE;YACnB,OAAO;SACV;QAED,KAAK,MAAM,MAAM,IAAI,gBAAgB,EAAE;YACnC,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,2BAA2B,CAAC,CAAC;YAChF,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAExD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;gBACtB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;gBAC/D,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;aACxC;SACJ;QAED,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,2CAA2C,CAAC,CAAC;IACtF,CAAC;IAEO,iBAAiB,CAAC,QAA6B,EAAE,YAA2B;QAChF,MAAM,WAAW,GAAwB,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;YAC/D,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,KAAK,CAC1B,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,CACnC,CAAC;YAEF,MAAM,UAAU,GAAG,IAAI,MAAM,CAAC,UAAU,CACpC,KAAK,EACL,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,kBAAkB,CAAC,OAAO,CACpC,CAAC;YAEF,UAAU,CAAC,MAAM,GAAG,uBAAuB,CAAC;YAC5C,UAAU,CAAC,IAAI,GAAG,cAAc,CAAC;YAEjC,OAAO,UAAU,CAAC;QACtB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC7D,CAAC;IAEO,kBAAkB,CAAC,QAAgB;QACvC,OAAO,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACvF,CAAC;CACJ;AA/DD,oDA+DC"}

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=ComponentInterfaces.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ComponentInterfaces.js","sourceRoot":"","sources":["../../src/types/ComponentInterfaces.ts"],"names":[],"mappings":""}

77
out/utils/FileResolver.js Normal file
View File

@@ -0,0 +1,77 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileResolver = void 0;
const vscode = __importStar(require("vscode"));
class FileResolver {
async getComponentFiles(document) {
const basePath = this.getBasePath(document.fileName);
const componentFiles = {};
if (document.fileName.endsWith('.component.ts')) {
componentFiles.typescript = document;
}
else if (document.fileName.endsWith('.component.html')) {
componentFiles.html = document;
}
else if (document.fileName.endsWith('.component.scss') || document.fileName.endsWith('.component.css')) {
componentFiles.styles = document;
}
// Try to find related files
try {
if (!componentFiles.typescript) {
const tsFile = await vscode.workspace.openTextDocument(basePath + '.component.ts');
componentFiles.typescript = tsFile;
}
if (!componentFiles.html) {
const htmlFile = await vscode.workspace.openTextDocument(basePath + '.component.html');
componentFiles.html = htmlFile;
}
if (!componentFiles.styles) {
try {
const scssFile = await vscode.workspace.openTextDocument(basePath + '.component.scss');
componentFiles.styles = scssFile;
}
catch {
try {
const cssFile = await vscode.workspace.openTextDocument(basePath + '.component.css');
componentFiles.styles = cssFile;
}
catch {
// No styles file found
}
}
}
}
catch (error) {
// Some files might not exist, which is fine
}
return componentFiles;
}
getBasePath(fileName) {
return fileName.replace(/\.(component\.(ts|html|scss|css))$/, '');
}
}
exports.FileResolver = FileResolver;
//# sourceMappingURL=FileResolver.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"FileResolver.js","sourceRoot":"","sources":["../../src/utils/FileResolver.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AAGjC,MAAa,YAAY;IACrB,KAAK,CAAC,iBAAiB,CAAC,QAA6B;QACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrD,MAAM,cAAc,GAAmB,EAAE,CAAC;QAE1C,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE;YAC7C,cAAc,CAAC,UAAU,GAAG,QAAQ,CAAC;SACxC;aAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE;YACtD,cAAc,CAAC,IAAI,GAAG,QAAQ,CAAC;SAClC;aAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE;YACtG,cAAc,CAAC,MAAM,GAAG,QAAQ,CAAC;SACpC;QAED,4BAA4B;QAC5B,IAAI;YACA,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE;gBAC5B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,GAAG,eAAe,CAAC,CAAC;gBACnF,cAAc,CAAC,UAAU,GAAG,MAAM,CAAC;aACtC;YACD,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE;gBACtB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,GAAG,iBAAiB,CAAC,CAAC;gBACvF,cAAc,CAAC,IAAI,GAAG,QAAQ,CAAC;aAClC;YACD,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE;gBACxB,IAAI;oBACA,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,GAAG,iBAAiB,CAAC,CAAC;oBACvF,cAAc,CAAC,MAAM,GAAG,QAAQ,CAAC;iBACpC;gBAAC,MAAM;oBACJ,IAAI;wBACA,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,QAAQ,GAAG,gBAAgB,CAAC,CAAC;wBACrF,cAAc,CAAC,MAAM,GAAG,OAAO,CAAC;qBACnC;oBAAC,MAAM;wBACJ,uBAAuB;qBAC1B;iBACJ;aACJ;SACJ;QAAC,OAAO,KAAK,EAAE;YACZ,4CAA4C;SAC/C;QAED,OAAO,cAAc,CAAC;IAC1B,CAAC;IAEO,WAAW,CAAC,QAAgB;QAChC,OAAO,QAAQ,CAAC,OAAO,CAAC,oCAAoC,EAAE,EAAE,CAAC,CAAC;IACtE,CAAC;CACJ;AA9CD,oCA8CC"}

View File

@@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SelectorMatcher = void 0;
class SelectorMatcher {
isSelectorUsed(cssSelector, usedSelectors) {
// Clean the CSS selector for comparison
const cleanSelector = this.cleanCSSSelector(cssSelector);
// Check for exact matches
if (usedSelectors.has(cleanSelector)) {
return true;
}
// Check for partial matches (class and ID selectors)
for (const used of usedSelectors) {
if (this.selectorsMatch(cleanSelector, used)) {
return true;
}
}
return false;
}
shouldIgnoreSelector(selector, ignoredSelectors) {
return ignoredSelectors.some(ignored => selector.includes(ignored) ||
selector.match(new RegExp(ignored.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))));
}
cleanCSSSelector(selector) {
// Remove pseudo-classes, pseudo-elements, and complex selectors
return selector
.replace(/::?[a-zA-Z-]+(\([^)]*\))?/g, '') // Remove pseudo-classes/elements
.replace(/\s*[>+~]\s*/g, ' ') // Simplify combinators
.replace(/\[.*?\]/g, '') // Remove attribute selectors
.trim();
}
selectorsMatch(cssSelector, usedSelector) {
// Extract class names and IDs
const cssClasses = cssSelector.match(/\.[a-zA-Z_-][a-zA-Z0-9_-]*/g) || [];
const cssIds = cssSelector.match(/#[a-zA-Z_-][a-zA-Z0-9_-]*/g) || [];
return [...cssClasses, ...cssIds].some(sel => usedSelector.includes(sel.substring(1)) // Remove . or # prefix
);
}
}
exports.SelectorMatcher = SelectorMatcher;
//# sourceMappingURL=SelectorMatcher.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"SelectorMatcher.js","sourceRoot":"","sources":["../../src/utils/SelectorMatcher.ts"],"names":[],"mappings":";;;AAAA,MAAa,eAAe;IACxB,cAAc,CAAC,WAAmB,EAAE,aAA0B;QAC1D,wCAAwC;QACxC,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;QAEzD,0BAA0B;QAC1B,IAAI,aAAa,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE;YAClC,OAAO,IAAI,CAAC;SACf;QAED,qDAAqD;QACrD,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE;YAC9B,IAAI,IAAI,CAAC,cAAc,CAAC,aAAa,EAAE,IAAI,CAAC,EAAE;gBAC1C,OAAO,IAAI,CAAC;aACf;SACJ;QAED,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,oBAAoB,CAAC,QAAgB,EAAE,gBAA0B;QAC7D,OAAO,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CACnC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC;YAC1B,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,CAAC,CAC7E,CAAC;IACN,CAAC;IAEO,gBAAgB,CAAC,QAAgB;QACrC,gEAAgE;QAChE,OAAO,QAAQ;aACV,OAAO,CAAC,4BAA4B,EAAE,EAAE,CAAC,CAAC,iCAAiC;aAC3E,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,uBAAuB;aACpD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,6BAA6B;aACrD,IAAI,EAAE,CAAC;IAChB,CAAC;IAEO,cAAc,CAAC,WAAmB,EAAE,YAAoB;QAC5D,8BAA8B;QAC9B,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,6BAA6B,CAAC,IAAI,EAAE,CAAC;QAC1E,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,4BAA4B,CAAC,IAAI,EAAE,CAAC;QAErE,OAAO,CAAC,GAAG,UAAU,EAAE,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CACzC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB;SAClE,CAAC;IACN,CAAC;CACJ;AA7CD,0CA6CC"}

View File

@@ -0,0 +1,55 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UnusedStyleFinder = void 0;
const vscode = __importStar(require("vscode"));
const SelectorMatcher_1 = require("./SelectorMatcher");
class UnusedStyleFinder {
constructor() {
this.selectorMatcher = new SelectorMatcher_1.SelectorMatcher();
}
findUnusedStyles(cssSelectors, usedSelectors, styleDocument) {
const unused = [];
const config = vscode.workspace.getConfiguration('angularUnusedStyles');
const ignoredSelectors = config.get('ignoredSelectors', []);
for (const [selector, position] of cssSelectors.entries()) {
if (this.selectorMatcher.shouldIgnoreSelector(selector, ignoredSelectors)) {
continue;
}
if (!this.selectorMatcher.isSelectorUsed(selector, usedSelectors)) {
unused.push({
selector,
line: position.line,
character: position.character,
length: position.length,
reason: `Style '${selector}' appears to be unused`
});
}
}
return unused;
}
}
exports.UnusedStyleFinder = UnusedStyleFinder;
//# sourceMappingURL=UnusedStyleFinder.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"UnusedStyleFinder.js","sourceRoot":"","sources":["../../src/utils/UnusedStyleFinder.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAAiC;AAEjC,uDAAoD;AAEpD,MAAa,iBAAiB;IAA9B;QACY,oBAAe,GAAG,IAAI,iCAAe,EAAE,CAAC;IA6BpD,CAAC;IA3BG,gBAAgB,CACZ,YAA2C,EAC3C,aAA0B,EAC1B,aAAkC;QAElC,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;QACxE,MAAM,gBAAgB,GAAa,MAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;QAEtE,KAAK,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,YAAY,CAAC,OAAO,EAAE,EAAE;YACvD,IAAI,IAAI,CAAC,eAAe,CAAC,oBAAoB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EAAE;gBACvE,SAAS;aACZ;YAED,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE;gBAC/D,MAAM,CAAC,IAAI,CAAC;oBACR,QAAQ;oBACR,IAAI,EAAE,QAAQ,CAAC,IAAI;oBACnB,SAAS,EAAE,QAAQ,CAAC,SAAS;oBAC7B,MAAM,EAAE,QAAQ,CAAC,MAAM;oBACvB,MAAM,EAAE,UAAU,QAAQ,wBAAwB;iBACrD,CAAC,CAAC;aACN;SACJ;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;CACJ;AA9BD,8CA8BC"}