Core linting functionality for processing Handlebars templates with configurable rules and comprehensive error reporting.
Main linting engine that processes templates and executes configured rules.
/**
* Main linting engine for Ember and Handlebars templates
* @param options - Configuration options for the linter instance
*/
class Linter {
constructor(options?: LinterOptions): Linter;
/**
* Load configuration from project files (.template-lintrc.js, etc.)
* Must be called before running verification
*/
loadConfig(): Promise<void>;
/**
* Lint a template and return violations
* @param options - Template content and metadata
* @returns Array of linting violations
*/
verify(options: VerifyOptions): Promise<LintResult[]>;
/**
* Lint a template and apply automatic fixes where possible
* @param options - Template content and metadata
* @returns Results with original source, fixed source, and remaining violations
*/
verifyAndFix(options: VerifyOptions): Promise<FixResult>;
}Configuration options for initializing a Linter instance.
interface LinterOptions {
/** Working directory for resolving config files and plugins (default: process.cwd()) */
workingDir?: string;
/** Console object for logging (default: console) */
console?: Console;
/** Inline rule specification in format "rule-name:severity" or "rule-name:[severity, config]" */
rule?: string;
/** Path to custom configuration file */
configPath?: string;
/** Allow inline configuration comments in templates (default: true) */
allowInlineConfig?: boolean;
/** Report unused template-lint-disable directives (default: false) */
reportUnusedDisableDirectives?: boolean;
/** Check HBS template literals in JavaScript/TypeScript files (default: true) */
checkHbsTemplateLiterals?: boolean;
}Options for template verification operations.
interface VerifyOptions {
/** Template source code to lint */
source: string;
/** File path for the template (used for configuration overrides and error reporting) */
filePath: string;
/** Working directory (defaults to linter's workingDir) */
workingDir?: string;
/** Configuration resolver for dynamic configuration */
configResolver?: ConfigResolver;
}
interface ConfigResolver {
/** Resolve EditorConfig settings for the file */
editorConfig?(): Record<string, any>;
}Structure of linting violation results.
interface LintResult {
/** Name of the rule that generated this violation */
rule: string;
/** Human-readable description of the violation */
message: string;
/** Line number where violation occurs (1-based) */
line: number;
/** Column number where violation occurs (0-based) */
column: number;
/** Severity level: -1=todo, 0=ignore, 1=warning, 2=error */
severity: -1 | 0 | 1 | 2;
/** Source code context where violation occurs */
source?: string;
/** Automatic fix information if available */
fix?: FixInfo;
/** End position for multi-character violations */
endLine?: number;
endColumn?: number;
/** Whether this is a fatal parsing error */
fatal?: boolean;
}
interface FixInfo {
/** Range to replace in the source */
range: [number, number];
/** Text to replace the range with */
text: string;
}Results from verifyAndFix operations.
interface FixResult {
/** Original template source */
source: string;
/** Fixed template source (may be same as source if no fixes applied) */
output: string;
/** Remaining violations that could not be auto-fixed */
messages: LintResult[];
/** Whether any fixes were applied */
isFixed: boolean;
}Usage Examples:
import Linter from "ember-template-lint";
// Basic linting
const linter = new Linter();
await linter.loadConfig();
const results = await linter.verify({
source: '<div>{{message}}</div>',
filePath: 'app/templates/component.hbs'
});
// Auto-fixing
const fixResult = await linter.verifyAndFix({
source: '<div class="example" >{{message}}</div>',
filePath: 'app/templates/component.hbs'
});
console.log('Fixed source:', fixResult.output);
console.log('Remaining issues:', fixResult.messages);
// Custom configuration
const customLinter = new Linter({
workingDir: '/path/to/project',
rule: 'no-bare-strings:error',
allowInlineConfig: false,
reportUnusedDisableDirectives: true
});
await customLinter.loadConfig();
// Lint JavaScript template literals
const jsResults = await customLinter.verify({
source: 'const template = hbs`<div>{{message}}</div>`;',
filePath: 'app/components/example.js'
});// Fatal errors (parsing failures) are included in results
interface FatalError extends LintResult {
fatal: true;
message: string;
source: string; // Stack trace
line?: number;
column?: number;
}Example with error handling:
try {
const results = await linter.verify({
source: '<div {{invalid-syntax}}',
filePath: 'broken-template.hbs'
});
const fatalErrors = results.filter(r => r.fatal);
const lintViolations = results.filter(r => !r.fatal);
if (fatalErrors.length > 0) {
console.error('Template parsing failed:', fatalErrors[0].message);
}
} catch (error) {
console.error('Linter configuration error:', error.message);
}