UNPKG

lwc-linter

Version:

A comprehensive CLI tool for linting Lightning Web Components v8.0.0+ with modern LWC patterns, decorators, lifecycle hooks, and Salesforce platform integration

231 lines 10.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.loadPerformanceRules = loadPerformanceRules; function loadPerformanceRules() { return [ { name: 'dom-query-optimization', description: 'Optimize DOM queries and avoid repeated querySelector calls', category: 'performance', severity: 'warn', fixable: false, check: (content, filePath, config) => { const issues = []; if (!filePath.endsWith('.js')) return issues; const lines = content.split('\n'); const querySelectors = {}; lines.forEach((line, index) => { // Find querySelector calls const querySelectorMatch = line.match(/querySelector\(['"`]([^'"`]+)['"`]\)/); if (querySelectorMatch) { const selector = querySelectorMatch[1]; if (!querySelectors[selector]) { querySelectors[selector] = []; } querySelectors[selector].push(index + 1); } }); // Check for repeated selectors Object.entries(querySelectors).forEach(([selector, lineNumbers]) => { if (lineNumbers.length > 2) { issues.push({ rule: 'dom-query-optimization', message: `Selector '${selector}' is used ${lineNumbers.length} times. Consider caching the result`, severity: 'warn', line: lineNumbers[0], fixable: false, category: 'performance' }); } }); // Check for querySelector inside loops lines.forEach((line, index) => { if ((line.includes('for (') || line.includes('forEach') || line.includes('while (')) && content.substring(content.indexOf(line)).includes('querySelector')) { issues.push({ rule: 'dom-query-optimization', message: 'Avoid DOM queries inside loops. Cache selectors outside the loop', severity: 'warn', line: index + 1, fixable: false, category: 'performance' }); } }); return issues; } }, { name: 'reactive-property-usage', description: 'Ensure proper usage of @track and @api decorators', category: 'performance', severity: 'warn', fixable: false, check: (content, filePath, config) => { const issues = []; if (!filePath.endsWith('.js')) return issues; const lines = content.split('\n'); lines.forEach((line, index) => { // Check for @track on primitive properties if (line.includes('@track') && (line.includes('= ""') || line.includes('= 0') || line.includes('= false') || line.includes('= true'))) { issues.push({ rule: 'reactive-property-usage', message: '@track is not needed for primitive values that are reassigned. Use @track only for objects/arrays', severity: 'info', line: index + 1, fixable: false, category: 'performance' }); } // Check for missing @track on objects/arrays if ((line.includes('= {}') || line.includes('= []')) && !lines[index - 1]?.includes('@track') && !line.includes('@track')) { issues.push({ rule: 'reactive-property-usage', message: 'Consider using @track for object/array properties that will be mutated', severity: 'info', line: index + 1, fixable: false, category: 'performance' }); } }); return issues; } }, { name: 'large-dom-check', description: 'Warn about potentially large DOM structures', category: 'performance', severity: 'warn', fixable: false, check: (content, filePath, config) => { const issues = []; if (!filePath.endsWith('.html')) return issues; const maxDomNodes = config.performance?.maxDomNodes || 1000; // Count DOM elements (simplified) const elementCount = (content.match(/<[^/][^>]*>/g) || []).length; if (elementCount > maxDomNodes) { issues.push({ rule: 'large-dom-check', message: `Template has ${elementCount} elements, which exceeds the recommended maximum of ${maxDomNodes}. Consider virtualization or pagination`, severity: 'warn', line: 1, fixable: false, category: 'performance' }); } // Check for large lists without virtualization const lines = content.split('\n'); lines.forEach((line, index) => { if (line.includes('for:each') && !content.includes('lightning-datatable')) { issues.push({ rule: 'large-dom-check', message: 'Consider using lightning-datatable or virtualization for large lists', severity: 'info', line: index + 1, fixable: false, category: 'performance' }); } }); return issues; } }, { name: 'bundle-size-check', description: 'Check for potential bundle size issues', category: 'performance', severity: 'info', fixable: false, check: (content, filePath, config) => { const issues = []; if (!filePath.endsWith('.js')) return issues; const maxBundleSize = config.performance?.maxBundleSize || 500000; const contentSize = Buffer.byteLength(content, 'utf8'); if (contentSize > maxBundleSize) { issues.push({ rule: 'bundle-size-check', message: `File size (${Math.round(contentSize / 1024)}KB) exceeds recommended maximum. Consider code splitting`, severity: 'info', line: 1, fixable: false, category: 'performance' }); } // Check for large imports const lines = content.split('\n'); lines.forEach((line, index) => { if (line.includes('import') && line.includes('*')) { issues.push({ rule: 'bundle-size-check', message: 'Avoid wildcard imports. Import only what you need to reduce bundle size', severity: 'info', line: index + 1, fixable: false, category: 'performance' }); } }); return issues; } }, { name: 'async-operation-check', description: 'Ensure proper handling of asynchronous operations', category: 'performance', severity: 'warn', fixable: false, check: (content, filePath, config) => { const issues = []; if (!filePath.endsWith('.js')) return issues; const lines = content.split('\n'); lines.forEach((line, index) => { // Check for synchronous operations that could block if (line.includes('XMLHttpRequest') && !line.includes('async')) { issues.push({ rule: 'async-operation-check', message: 'Use async/await or fetch() instead of synchronous XMLHttpRequest', severity: 'warn', line: index + 1, fixable: false, category: 'performance' }); } // Check for missing await on async operations if (line.includes('fetch(') && !line.includes('await') && !line.includes('.then(')) { issues.push({ rule: 'async-operation-check', message: 'Fetch calls should use await or .then() for proper async handling', severity: 'warn', line: index + 1, fixable: false, category: 'performance' }); } // Check for heavy operations in render cycles if ((line.includes('renderedCallback') || line.includes('render()')) && (line.includes('sort(') || line.includes('filter(') || line.includes('map('))) { issues.push({ rule: 'async-operation-check', message: 'Avoid heavy computations in render cycles. Consider memoization or computed properties', severity: 'warn', line: index + 1, fixable: false, category: 'performance' }); } }); return issues; } } ]; } //# sourceMappingURL=performance.js.map