This document provides detailed API documentation for developers working with or extending the HQLint VS Code extension.
- Architecture Overview
- Core Modules
- Extension API
- Linting System
- Formatting System
- Utility Functions
- Configuration
HQLint follows a modular architecture with clear separation of concerns:
src/
├── extension.ts # Extension entry point & VS Code integration
├── linter.ts # Linting orchestration
├── formatter.ts # SQL formatting using sql-formatter
├── diagnostics.ts # Diagnostic management
├── logger.ts # Logging system
├── hoverProvider.ts # Hover documentation provider
├── signatureProvider.ts # Function signature help
├── snippets.ts # Code snippets
├── linter/
│ └── rules/ # Modular lint rules
│ ├── baseRule.ts # Base class for all rules
│ ├── keywordCasingRule.ts
│ ├── semicolonRule.ts
│ ├── stringLiteralRule.ts
│ ├── parenthesesRule.ts
│ └── trailingWhitespaceRule.ts
└── utils/
└── stringUtils.ts # Pure utility functions
Provides structured logging with configurable log levels.
Constructor:
constructor(channelName: string = 'HQL')Methods:
debug(message: string, data?: any): void- Log debug informationinfo(message: string, data?: any): void- Log informational messageswarn(message: string, data?: any): void- Log warningserror(message: string, error?: any): void- Log errors with stack tracesshow(): void- Show the output channeldispose(): void- Cleanup resources
Enum: LogLevel
enum LogLevel {
Debug = 0,
Info = 1,
Warn = 2,
Error = 3
}Configuration:
hql.logLevel: Set log level (debug/info/warn/error)
Example:
const logger = new Logger('HQL');
logger.info('Extension activated');
logger.error('Formatting failed', error);Manages VS Code diagnostics lifecycle.
Constructor:
constructor()Methods:
set(uri: vscode.Uri, diagnostics: vscode.Diagnostic[]): void- Set diagnostics for a documentclear(uri: vscode.Uri): void- Clear diagnostics for a documentdispose(): void- Dispose of all diagnostics
Example:
const diagnosticsProvider = new HQLDiagnosticsProvider();
diagnosticsProvider.set(document.uri, [diagnostic1, diagnostic2]);Exported Functions:
Called when extension is activated. Sets up:
- Document formatting provider
- Range formatting provider
- Completion provider
- Hover provider
- Signature help provider
- Code action provider
- Event listeners for document changes
Parameters:
context: VS Code extension context for subscriptions
Called when extension is deactivated. Cleanup is handled automatically through context subscriptions.
Registered Commands:
hql.formatDocument- Format current HQL documenthql.lintDocument- Lint current HQL document
Orchestrates linting rules and generates diagnostics.
Constructor:
constructor(diagnosticsProvider: HQLDiagnosticsProvider, logger: Logger)Public Methods:
lint(document: vscode.TextDocument): void- Lint a document and generate diagnostics
Private Methods:
initializeRules(): LintRule[]- Initialize all available lint rulesgetEnabledRules(): LintRule[]- Get rules enabled by configurationgetRuleConfigKey(ruleName: string): string- Convert rule name to config key
Configuration:
hql.linting.enabled- Enable/disable lintinghql.linting.severity- Default severity levelhql.linting.maxFileSize- Maximum file size to lint (bytes)hql.linting.rules.*- Individual rule toggles
Example:
const linter = new HQLLinter(diagnosticsProvider, logger);
linter.lint(document);All lint rules implement the LintRule interface.
interface LintRule {
name: string;
description: string;
check(context: LintContext): vscode.Diagnostic | null;
}interface LintContext {
document: vscode.TextDocument;
lineNumber: number;
lineText: string;
logger: Logger;
}All rules extend this abstract class.
Protected Methods:
getSeverity(): vscode.DiagnosticSeverity- Get configured severitycreateDiagnostic(range, message, severity?): vscode.Diagnostic- Create diagnostic
Example Rule Implementation:
export class MyCustomRule extends BaseLintRule {
name = 'my-custom-rule';
description = 'Checks for custom patterns';
check(context: LintContext): vscode.Diagnostic | null {
try {
// Implement your rule logic
if (/* condition */) {
const range = new vscode.Range(/*...*/);
return this.createDiagnostic(range, 'Issue detected');
}
return null;
} catch (error) {
context.logger.error(`Error in ${this.name}`, error);
return null;
}
}
}-
KeywordCasingRule (
keyword-casing)- Checks for lowercase SQL keywords
- Config:
hql.linting.rules.keywordCasing
-
SemicolonRule (
semicolon)- Checks for missing semicolons
- Config:
hql.linting.rules.semicolon
-
StringLiteralRule (
string-literal)- Checks for unclosed string literals
- Config:
hql.linting.rules.stringLiteral
-
ParenthesesRule (
parentheses)- Checks for unbalanced parentheses
- Config:
hql.linting.rules.parentheses
-
TrailingWhitespaceRule (
trailing-whitespace)- Checks for trailing whitespace
- Config:
hql.linting.rules.trailingWhitespace
Uses the sql-formatter library with Hive dialect.
Constructor:
constructor(logger: Logger)Public Methods:
format(document: vscode.TextDocument): vscode.TextEdit[]- Format entire documentformatRange(document: vscode.TextDocument, range: vscode.Range): vscode.TextEdit[]- Format a range
Private Methods:
getConfig()- Read formatting configurationformatText(text: string): string- Format text using sql-formatter
Configuration Options:
hql.formatting.enabled- Enable/disable formattinghql.formatting.tabWidth- Indentation width (1-8)hql.formatting.useTabs- Use tabs instead of spaceshql.formatting.keywordCase- Keyword case (upper/lower/preserve)hql.formatting.dataTypeCase- Data type casehql.formatting.functionCase- Function casehql.formatting.identifierCase- Identifier casehql.formatting.indentStyle- Indent style (standard/tabularLeft/tabularRight)hql.formatting.linesBetweenQueries- Blank lines between queries (0-5)hql.formatting.denseOperators- Dense operator spacinghql.formatting.newlineBeforeSemicolon- Semicolon placement
Example:
const formatter = new HQLFormatter(logger);
const edits = formatter.format(document);Pure utility functions for string parsing and validation.
countUnescapedQuotes(text: string, quoteChar: string): number
Counts unescaped quotes in a string, handling escape sequences correctly.
countUnescapedQuotes("'O\\'Brien'", "'") // Returns 2removeComments(text: string): string
Removes SQL comments (line and block) from text.
removeComments("SELECT * -- comment") // Returns "SELECT * "isQuoteEscaped(text: string, position: number): boolean
Checks if a quote at a position is escaped.
isQuoteEscaped("'O\\'Brien'", 3) // Returns truevalidateConfigNumber(value: number, min: number, max: number, defaultValue: number): number
Validates and clamps configuration numbers.
validateConfigNumber(10, 1, 5, 2) // Returns 5 (clamped)findLastOccurrence(text: string, char: string): number
Finds the last occurrence of a character.
findLastOccurrence("hello", "l") // Returns 3countOutsideStrings(text: string, char: string): number
Counts character occurrences outside of string literals.
countOutsideStrings("'a+b' + c", "+") // Returns 1All configuration is namespaced under hql.*:
{
"hql.linting.enabled": true,
"hql.linting.severity": "Warning",
"hql.linting.maxFileSize": 1048576,
"hql.linting.rules.keywordCasing": true,
"hql.linting.rules.semicolon": true,
"hql.linting.rules.stringLiteral": true,
"hql.linting.rules.parentheses": true,
"hql.linting.rules.trailingWhitespace": true
}{
"hql.formatting.enabled": true,
"hql.formatting.tabWidth": 2,
"hql.formatting.useTabs": false,
"hql.formatting.keywordCase": "upper",
"hql.formatting.dataTypeCase": "upper",
"hql.formatting.functionCase": "upper",
"hql.formatting.identifierCase": "preserve",
"hql.formatting.indentStyle": "standard",
"hql.formatting.linesBetweenQueries": 1,
"hql.formatting.denseOperators": false,
"hql.formatting.newlineBeforeSemicolon": false
}{
"hql.logLevel": "info"
}const config = vscode.workspace.getConfiguration('hql.linting');
const enabled = config.get<boolean>('enabled', true);const config = vscode.workspace.getConfiguration('hql.formatting');
await config.update('keywordCase', 'lower', vscode.ConfigurationTarget.Global);Provides hover documentation for HQL keywords and functions.
Function:
export function provideHover(
document: vscode.TextDocument,
position: vscode.Position
): vscode.Hover | nullProvides function signature help.
Function:
export function provideSignatureHelp(
document: vscode.TextDocument,
position: vscode.Position
): vscode.SignatureHelp | nullProvides code snippets for common HQL patterns.
Function:
export function getHQLSnippets(): vscode.CompletionItem[]Available snippets:
- CREATE TABLE
- INSERT OVERWRITE
- SELECT JOIN
- WINDOW FUNCTION
- CASE WHEN
- LATERAL VIEW EXPLODE
- WITH CTE
- GROUP BY AGGREGATE
- UNION
- PARTITIONED BY
src/test/
├── runTest.ts # Test runner entry point
└── suite/
├── index.ts # Mocha test suite setup
├── stringUtils.test.ts # Unit tests for string utilities
└── extension.test.ts # Integration tests
npm testimport * as assert from 'assert';
import { countUnescapedQuotes } from '../../utils/stringUtils';
suite('My Test Suite', () => {
test('Should do something', () => {
const result = countUnescapedQuotes("'test'", "'");
assert.strictEqual(result, 2);
});
});- Create a new file in
src/linter/rules/ - Extend
BaseLintRule - Implement
check()method - Add to
initializeRules()inlinter.ts - Add configuration in
package.json
- Register in
contributes.commandsinpackage.json - Register command handler in
extension.tsusingvscode.commands.registerCommand() - Add to
context.subscriptions
- Add to
contributes.configuration.propertiesinpackage.json - Access using
vscode.workspace.getConfiguration()
- Debouncing: Linting is debounced by 500ms to avoid excessive runs
- File Size Limits: Files larger than
maxFileSizeare skipped - Lazy Loading: Extension only activates on
.hqlor.hivefiles - Rule Filtering: Only enabled rules are executed
All public methods follow this pattern:
try {
// Operation
} catch (error) {
logger.error('Error message', error);
vscode.window.showErrorMessage('User-friendly message');
return []; // Graceful degradation
}- Always log errors using the Logger
- Use pure functions for testable logic
- Follow the rule interface for consistency
- Respect configuration settings
- Handle edge cases gracefully
- Document public APIs with JSDoc comments
- Write tests for new features
See CONTRIBUTING.md for contribution guidelines.
MIT License - See LICENSE file for details.