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

276 lines 13.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.loadESLintPrettierRules = loadESLintPrettierRules; function loadESLintPrettierRules() { return [ { name: 'eslint-integration', description: 'Run ESLint on JavaScript files for comprehensive code analysis', category: 'code-quality', severity: 'warn', fixable: true, check: (content, filePath, config) => { const issues = []; if (!filePath.endsWith('.js')) return issues; // Basic ESLint-style checks const lines = content.split('\n'); lines.forEach((line, index) => { // Check for double quotes when single quotes should be used if (line.includes('"') && !line.includes("'") && !line.trim().startsWith('//')) { const doubleQuoteMatches = line.match(/"/g); if (doubleQuoteMatches && doubleQuoteMatches.length >= 2) { issues.push({ rule: 'eslint-integration', message: 'Use single quotes instead of double quotes', severity: 'warn', line: index + 1, fixable: true, category: 'code-quality', }); } } // Check for missing semicolons if (line.trim() && !line.trim().startsWith('//') && !line.trim().startsWith('*') && !line.trim().startsWith('/*') && !line.trim().endsWith(';') && !line.trim().endsWith('{') && !line.trim().endsWith('}') && !line.includes('if (') && !line.includes('for (') && !line.includes('while (') && !line.includes('else') && !line.includes('try') && !line.includes('catch') && !line.includes('finally') && (line.includes('=') || line.includes('return') || line.includes('throw'))) { issues.push({ rule: 'eslint-integration', message: 'Missing semicolon at end of statement', severity: 'error', line: index + 1, fixable: true, category: 'code-quality', }); } // Check for == instead of === if (line.includes('==') && !line.includes('===') && !line.includes('!==') && !line.trim().startsWith('//')) { issues.push({ rule: 'eslint-integration', message: 'Use strict equality (===) instead of loose equality (==)', severity: 'error', line: index + 1, fixable: true, category: 'code-quality', }); } // Check for complex conditions (multiple && or ||) const complexCondition = (line.match(/&&/g) || []).length + (line.match(/\|\|/g) || []).length; if (complexCondition > 3) { issues.push({ rule: 'eslint-integration', message: 'Complex condition detected. Consider breaking into smaller parts for readability', severity: 'warn', line: index + 1, fixable: false, category: 'code-quality', }); } }); return issues; }, fix: (content, issues) => { let fixedContent = content; issues.forEach(issue => { if (issue.rule === 'eslint-integration' && issue.fixable) { if (issue.message.includes('single quotes')) { // Fix double quotes to single quotes fixedContent = fixedContent.replace(/"/g, "'"); } else if (issue.message.includes('semicolon')) { // Add missing semicolons const lines = fixedContent.split('\n'); if (issue.line && lines[issue.line - 1]) { lines[issue.line - 1] = lines[issue.line - 1].trimEnd() + ';'; fixedContent = lines.join('\n'); } } else if (issue.message.includes('strict equality')) { // Fix == to === fixedContent = fixedContent.replace(/([^=!])={2}([^=])/g, '$1===$2'); } } }); return fixedContent; }, }, { name: 'prettier-formatting', description: 'Ensure consistent code formatting with Prettier standards', category: 'code-quality', severity: 'warn', fixable: true, check: (content, filePath, config) => { const issues = []; const lines = content.split('\n'); lines.forEach((line, index) => { // Check for inconsistent indentation (mixing tabs and spaces) if (line.match(/^\t+ +/) || line.match(/^ +\t/)) { issues.push({ rule: 'prettier-formatting', message: 'Inconsistent indentation: mixing tabs and spaces', severity: 'warn', line: index + 1, fixable: true, category: 'code-quality', }); } // Check for trailing spaces if (line.match(/\s+$/)) { issues.push({ rule: 'prettier-formatting', message: 'Trailing whitespace detected', severity: 'warn', line: index + 1, fixable: true, category: 'code-quality', }); } // Check for multiple consecutive empty lines if (line.trim() === '' && lines[index + 1]?.trim() === '' && lines[index + 2]?.trim() === '') { issues.push({ rule: 'prettier-formatting', message: 'Too many consecutive empty lines', severity: 'warn', line: index + 1, fixable: true, category: 'code-quality', }); } // Check for long lines (over 100 characters) if (line.length > 100 && !line.trim().startsWith('//')) { issues.push({ rule: 'prettier-formatting', message: 'Line exceeds maximum length of 100 characters', severity: 'info', line: index + 1, fixable: false, category: 'code-quality', }); } // Check for missing space after commas if (line.match(/,\S/) && !line.trim().startsWith('//')) { issues.push({ rule: 'prettier-formatting', message: 'Missing space after comma', severity: 'warn', line: index + 1, fixable: true, category: 'code-quality', }); } // Check for missing space around operators if (line.match(/\S[+\-*/=]\S/) && !line.includes('++') && !line.includes('--') && !line.trim().startsWith('//')) { issues.push({ rule: 'prettier-formatting', message: 'Missing space around operators', severity: 'warn', line: index + 1, fixable: true, category: 'code-quality', }); } }); return issues; }, fix: (content, issues) => { let fixedContent = content; // Fix trailing spaces fixedContent = fixedContent.replace(/\s+$/gm, ''); // Fix multiple consecutive empty lines fixedContent = fixedContent.replace(/\n{3,}/g, '\n\n'); // Fix missing space after commas fixedContent = fixedContent.replace(/,(\S)/g, ', $1'); // Fix missing space around operators (basic cases) fixedContent = fixedContent.replace(/(\S)([+\-*/=])(\S)/g, '$1 $2 $3'); // Convert tabs to spaces (2 spaces) fixedContent = fixedContent.replace(/\t/g, ' '); return fixedContent; }, }, { name: 'import-organization', description: 'Ensure proper import statement organization and formatting', category: 'code-quality', severity: 'info', fixable: true, check: (content, filePath, config) => { const issues = []; if (!filePath.endsWith('.js')) return issues; const lines = content.split('\n'); const importLines = []; lines.forEach((line, index) => { if (line.trim().startsWith('import ')) { importLines.push({ line: line.trim(), index }); } }); // Check if imports are at the top of the file if (importLines.length > 0) { const firstImportIndex = importLines[0].index; for (let i = 0; i < firstImportIndex; i++) { if (lines[i].trim() && !lines[i].trim().startsWith('//') && !lines[i].trim().startsWith('/*')) { issues.push({ rule: 'import-organization', message: 'Import statements should be at the top of the file', severity: 'warn', line: firstImportIndex + 1, fixable: false, category: 'code-quality', }); break; } } } // Check for unused imports (basic check) importLines.forEach(({ line, index }) => { const importMatch = line.match(/import\s+(?:{([^}]+)}|\*\s+as\s+(\w+)|(\w+))/); if (importMatch) { const importedNames = importMatch[1] ? importMatch[1].split(',').map(name => name.trim()) : [importMatch[2] || importMatch[3]]; importedNames.forEach(name => { if (name && !content.includes(name.replace(/\s*as\s+\w+/, ''))) { issues.push({ rule: 'import-organization', message: `Unused import '${name}'`, severity: 'warn', line: index + 1, fixable: true, category: 'code-quality', }); } }); } }); return issues; }, fix: (content, issues) => { // Basic fix: remove lines with unused imports let fixedContent = content; const lines = fixedContent.split('\n'); issues.forEach(issue => { if (issue.rule === 'import-organization' && issue.message.includes('Unused import') && issue.line) { lines[issue.line - 1] = ''; } }); // Remove empty lines where imports were removed fixedContent = lines.join('\n').replace(/\n\s*\n/g, '\n'); return fixedContent; }, }, ]; } //# sourceMappingURL=eslint-prettier.js.map