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
161 lines • 6.52 kB
JavaScript
;
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 () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileProcessor = void 0;
const acorn = __importStar(require("acorn"));
const htmlparser2_1 = require("htmlparser2");
const rule_manager_1 = require("./rule-manager");
class FileProcessor {
constructor(config) {
this.config = config;
this.ruleManager = new rule_manager_1.RuleManager(config);
}
async processJavaScript(content, filePath) {
const issues = [];
try {
// Preprocess LWC decorators for better parsing compatibility
const cleanedContent = this.preprocessLWCDecorators(content);
// Parse JavaScript with Acorn
const ast = acorn.parse(cleanedContent, {
ecmaVersion: 2022,
sourceType: 'module',
locations: true,
allowHashBang: true,
allowReturnOutsideFunction: true
});
// Apply JavaScript-specific rules
issues.push(...this.ruleManager.checkJavaScriptRules(content, filePath, ast));
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
// Filter out LWC decorator-related syntax errors
if (this.isLWCDecoratorError(errorMessage)) {
// Skip this error - it's just LWC decorators which are valid
console.log(`ℹ️ Skipping LWC decorator syntax in ${filePath}`);
}
else {
issues.push({
rule: 'syntax-error',
message: `JavaScript syntax error: ${errorMessage}`,
severity: 'error',
category: 'code-quality'
});
}
}
return issues;
}
preprocessLWCDecorators(content) {
// Remove LWC v8.0.0+ decorators to make the code parseable by standard JavaScript parser
let cleanedContent = content
// Core LWC decorators
.replace(/@api\s+/g, '/* @api */ ')
.replace(/@track\s+/g, '/* @track */ ')
.replace(/@wire\s*\([^)]*\)\s*/g, '/* @wire(...) */ ')
// Enhanced LWC v8.0.0+ decorators
.replace(/@consume\s*\([^)]*\)\s*/g, '/* @consume(...) */ ')
.replace(/@provide\s*\([^)]*\)\s*/g, '/* @provide(...) */ ')
.replace(/@reactive\s+/g, '/* @reactive */ ')
// Salesforce platform decorators
.replace(/@salesforceUx\s*(\([^)]*\))?\s*/g, '/* @salesforceUx$1 */ ')
.replace(/@namespace\s*(\([^)]*\))?\s*/g, '/* @namespace$1 */ ')
// Developer-defined custom decorators (common patterns)
.replace(/@([a-zA-Z][a-zA-Z0-9]*)\s*(\([^)]*\))?\s*/g, '/* @$1$2 */ ');
return cleanedContent;
}
isLWCDecoratorError(errorMessage) {
// Check if the error is related to LWC v8.0.0+ decorators
const lwcDecoratorPatterns = [
/Unexpected character '@'/,
/Unexpected token '@'/,
/@api/,
/@track/,
/@wire/,
/@consume/,
/@provide/,
/@reactive/,
/@salesforceUx/,
/@namespace/,
/Invalid left-hand side in assignment/,
/Unexpected token, expected/,
/Decorators are not valid here/,
/Unexpected decorator/
];
return lwcDecoratorPatterns.some(pattern => pattern.test(errorMessage));
}
async processHTML(content, filePath) {
const issues = [];
try {
// Parse HTML with htmlparser2
const document = (0, htmlparser2_1.parseDocument)(content, {
withStartIndices: true,
withEndIndices: true
});
// Apply HTML-specific rules
issues.push(...this.ruleManager.checkHTMLRules(content, filePath, document));
// Apply accessibility rules
if (this.config.accessibility?.enabled) {
issues.push(...this.ruleManager.checkAccessibilityRules(content, filePath, document));
}
}
catch (error) {
issues.push({
rule: 'syntax-error',
message: `HTML parsing error: ${error instanceof Error ? error.message : error}`,
severity: 'error',
category: 'code-quality'
});
}
return issues;
}
async processCSS(content, filePath) {
const issues = [];
try {
// Simple CSS processing without css-tree
// Apply CSS-specific rules
issues.push(...this.ruleManager.checkCSSRules(content, filePath, null));
}
catch (error) {
issues.push({
rule: 'syntax-error',
message: `CSS parsing error: ${error instanceof Error ? error.message : error}`,
severity: 'error',
category: 'code-quality'
});
}
return issues;
}
}
exports.FileProcessor = FileProcessor;
//# sourceMappingURL=file-processor.js.map