Initial commit
This commit is contained in:
34
out/analyzer/AngularComponentAnalyzer.js
Normal file
34
out/analyzer/AngularComponentAnalyzer.js
Normal 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
|
||||
1
out/analyzer/AngularComponentAnalyzer.js.map
Normal file
1
out/analyzer/AngularComponentAnalyzer.js.map
Normal 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
121
out/analyzer/CSSAnalyzer.js
Normal 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
|
||||
1
out/analyzer/CSSAnalyzer.js.map
Normal file
1
out/analyzer/CSSAnalyzer.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"CSSAnalyzer.js","sourceRoot":"","sources":["../../src/analyzer/CSSAnalyzer.ts"],"names":[],"mappings":"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"}
|
||||
42
out/analyzer/HTMLAnalyzer.js
Normal file
42
out/analyzer/HTMLAnalyzer.js
Normal 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
|
||||
1
out/analyzer/HTMLAnalyzer.js.map
Normal file
1
out/analyzer/HTMLAnalyzer.js.map
Normal 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"}
|
||||
39
out/analyzer/TypeScriptAnalyzer.js
Normal file
39
out/analyzer/TypeScriptAnalyzer.js
Normal 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
|
||||
1
out/analyzer/TypeScriptAnalyzer.js.map
Normal file
1
out/analyzer/TypeScriptAnalyzer.js.map
Normal 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
66
out/extension.js
Normal 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
1
out/extension.js.map
Normal 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"}
|
||||
71
out/providers/UnusedStylesProvider.js
Normal file
71
out/providers/UnusedStylesProvider.js
Normal 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
|
||||
1
out/providers/UnusedStylesProvider.js.map
Normal file
1
out/providers/UnusedStylesProvider.js.map
Normal 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"}
|
||||
3
out/types/ComponentInterfaces.js
Normal file
3
out/types/ComponentInterfaces.js
Normal file
@@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
//# sourceMappingURL=ComponentInterfaces.js.map
|
||||
1
out/types/ComponentInterfaces.js.map
Normal file
1
out/types/ComponentInterfaces.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"ComponentInterfaces.js","sourceRoot":"","sources":["../../src/types/ComponentInterfaces.ts"],"names":[],"mappings":""}
|
||||
77
out/utils/FileResolver.js
Normal file
77
out/utils/FileResolver.js
Normal 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
|
||||
1
out/utils/FileResolver.js.map
Normal file
1
out/utils/FileResolver.js.map
Normal 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"}
|
||||
41
out/utils/SelectorMatcher.js
Normal file
41
out/utils/SelectorMatcher.js
Normal 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
|
||||
1
out/utils/SelectorMatcher.js.map
Normal file
1
out/utils/SelectorMatcher.js.map
Normal 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"}
|
||||
55
out/utils/UnusedStyleFinder.js
Normal file
55
out/utils/UnusedStyleFinder.js
Normal 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
|
||||
1
out/utils/UnusedStyleFinder.js.map
Normal file
1
out/utils/UnusedStyleFinder.js.map
Normal 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"}
|
||||
Reference in New Issue
Block a user