rawsql-ts
Version:
[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.
292 lines • 12.2 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseToPosition = parseToPosition;
exports.getCursorContext = getCursorContext;
exports.resolveScope = resolveScope;
exports.splitQueries = splitQueries;
exports.getIntelliSenseInfo = getIntelliSenseInfo;
exports.getCompletionSuggestions = getCompletionSuggestions;
const CursorContextAnalyzer_1 = require("./CursorContextAnalyzer");
const ScopeResolver_1 = require("./ScopeResolver");
const PositionAwareParser_1 = require("./PositionAwareParser");
const MultiQuerySplitter_1 = require("./MultiQuerySplitter");
const TextPositionUtils_1 = require("./TextPositionUtils");
/**
* Convenience API for SQL IntelliSense integration
*
* Provides simplified, high-level functions that combine the functionality
* of the various position-aware parsing components for easy integration
* with Monaco Editor and other code editors.
*
* @example
* ```typescript
* import { parseToPosition, getCursorContext, resolveScope, splitQueries } from 'rawsql-ts';
*
* // Parse incomplete SQL with error recovery
* const sql = "SELECT u.name FROM users u WHERE u.";
* const parseResult = parseToPosition(sql, sql.length, { errorRecovery: true });
*
* // Get cursor context for completion suggestions
* const context = getCursorContext(sql, sql.length);
* console.log(context.isAfterDot); // true
* console.log(context.precedingIdentifier); // "u"
*
* // Get scope information for table/column completion
* const scope = resolveScope(sql, sql.length);
* console.log(scope.availableTables); // [{ name: 'users', alias: 'u' }]
*
* // Handle multi-query editor
* const multiSQL = "SELECT 1; SELECT 2;";
* const queries = splitQueries(multiSQL);
* const activeQuery = queries.getActive(12); // Get query at position
* ```
*/
/**
* Parse SQL up to cursor position with error recovery
*
* Combines position-aware parsing with error recovery to handle incomplete SQL
* that users are actively typing. Ideal for providing IntelliSense in editors.
*
* @param sql - SQL text to parse
* @param cursorPosition - Cursor position (character offset or line/column)
* @param options - Parsing options including error recovery settings
* @returns Parse result with position-specific information
*/
function parseToPosition(sql, cursorPosition, options = {}) {
return PositionAwareParser_1.PositionAwareParser.parseToPosition(sql, cursorPosition, options);
}
/**
* Analyze cursor context for IntelliSense completion suggestions
*
* Determines what type of completions should be offered at the cursor position
* based on SQL syntax context (SELECT clause, WHERE condition, etc.).
*
* @param sql - SQL text to analyze
* @param cursorPosition - Cursor position (character offset or line/column)
* @returns Cursor context information for completion logic
*/
function getCursorContext(sql, cursorPosition) {
if (typeof cursorPosition === 'number') {
return CursorContextAnalyzer_1.CursorContextAnalyzer.analyzeIntelliSense(sql, cursorPosition);
}
else {
return CursorContextAnalyzer_1.CursorContextAnalyzer.analyzeIntelliSenseAt(sql, cursorPosition);
}
}
/**
* Resolve scope information at cursor position
*
* Provides comprehensive information about available tables, CTEs, and columns
* at the specified cursor position for intelligent completion suggestions.
*
* @param sql - SQL text to analyze
* @param cursorPosition - Cursor position (character offset or line/column)
* @returns Complete scope information including available tables and columns
*/
function resolveScope(sql, cursorPosition) {
if (typeof cursorPosition === 'number') {
return ScopeResolver_1.ScopeResolver.resolve(sql, cursorPosition);
}
else {
return ScopeResolver_1.ScopeResolver.resolveAt(sql, cursorPosition);
}
}
/**
* Split multi-query SQL text into individual queries
*
* Handles SQL editors that contain multiple statements separated by semicolons.
* Properly handles string literals and comments containing semicolons.
*
* @param sql - Multi-query SQL text
* @returns Collection of individual queries with position information
*/
function splitQueries(sql) {
return MultiQuerySplitter_1.MultiQuerySplitter.split(sql);
}
/**
* Get IntelliSense information for a cursor position in multi-query context
*
* Combines query splitting, context analysis, and scope resolution to provide
* complete IntelliSense information for a cursor position in multi-query SQL.
*
* @param sql - Multi-query SQL text
* @param cursorPosition - Cursor position
* @param options - Parsing options
* @returns Complete IntelliSense information or undefined if position is invalid
*/
function getIntelliSenseInfo(sql, cursorPosition, options = {}) {
const charPos = typeof cursorPosition === 'number'
? cursorPosition
: TextPositionUtils_1.TextPositionUtils.lineColumnToCharOffset(sql, cursorPosition);
if (charPos === -1) {
return undefined;
}
// Split queries and find the active one
const queries = splitQueries(sql);
const activeQuery = queries.getActive(charPos);
if (!activeQuery) {
return undefined;
}
// Calculate relative position within the active query
const relativePosition = charPos - activeQuery.start;
const querySQL = activeQuery.sql;
// Get IntelliSense information for the active query
const context = getCursorContext(querySQL, relativePosition);
const scope = resolveScope(querySQL, relativePosition);
const parseResult = parseToPosition(querySQL, relativePosition, options);
return {
context,
scope,
parseResult,
currentQuery: querySQL,
relativePosition
};
}
/**
* Get completion suggestions based on cursor context and scope
*
* Uses the new IntelliSense interface to provide targeted completion suggestions.
* This function leverages the suggestion-based design to efficiently determine
* what completions should be offered.
*
* @param sql - SQL text
* @param cursorPosition - Cursor position
* @returns Array of completion suggestions with context information
*/
function getCompletionSuggestions(sql, cursorPosition) {
const charPos = typeof cursorPosition === 'number'
? cursorPosition
: TextPositionUtils_1.TextPositionUtils.lineColumnToCharOffset(sql, cursorPosition);
if (charPos === -1) {
return [];
}
const intelliSenseContext = CursorContextAnalyzer_1.CursorContextAnalyzer.analyzeIntelliSense(sql, charPos);
const scope = resolveScope(sql, cursorPosition);
const suggestions = [];
// Add keyword suggestions
if (intelliSenseContext.suggestKeywords) {
// Add required keywords if specified
if (intelliSenseContext.requiredKeywords) {
intelliSenseContext.requiredKeywords.forEach(keyword => {
suggestions.push({
type: 'keyword',
value: keyword,
detail: `Required keyword: ${keyword}`
});
});
}
else {
// Add general contextual keywords based on token context
const generalKeywords = getGeneralKeywords(intelliSenseContext);
generalKeywords.forEach(keyword => {
suggestions.push({
type: 'keyword',
value: keyword.value,
detail: keyword.detail
});
});
}
}
// Add table suggestions
if (intelliSenseContext.suggestTables) {
scope.availableTables.forEach(table => {
suggestions.push({
type: 'table',
value: table.alias || table.name,
detail: `Table: ${table.fullName}`,
documentation: `Available table${table.alias ? ` (alias: ${table.alias})` : ''}`
});
});
// Add CTE suggestions
scope.availableCTEs.forEach(cte => {
suggestions.push({
type: 'cte',
value: cte.name,
detail: `CTE: ${cte.name}`,
documentation: `Common Table Expression${cte.columns ? ` with columns: ${cte.columns.join(', ')}` : ''}`
});
});
}
// Add column suggestions
if (intelliSenseContext.suggestColumns) {
if (intelliSenseContext.tableScope) {
// Specific table/alias column completion
const columns = scope.visibleColumns.filter(col => col.tableName === intelliSenseContext.tableScope ||
col.tableAlias === intelliSenseContext.tableScope);
columns.forEach(col => {
suggestions.push({
type: 'column',
value: col.name,
detail: `Column: ${col.fullReference}`,
documentation: `Column from ${col.tableName}${col.type ? ` (${col.type})` : ''}`
});
});
}
else {
// General column completion
scope.visibleColumns.forEach(col => {
suggestions.push({
type: 'column',
value: col.name === '*' ? '*' : `${col.tableAlias || col.tableName}.${col.name}`,
detail: `Column: ${col.fullReference}`,
documentation: `Column from ${col.tableName}`
});
});
}
}
return suggestions;
}
/**
* Get general keyword suggestions based on IntelliSense context
*/
function getGeneralKeywords(context) {
var _a, _b, _c, _d;
// Determine context from token information
const prevToken = (_b = (_a = context.previousToken) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.toLowerCase();
const currentToken = (_d = (_c = context.currentToken) === null || _c === void 0 ? void 0 : _c.value) === null || _d === void 0 ? void 0 : _d.toLowerCase();
// SELECT context - aggregate functions and keywords
if (prevToken === "select" || currentToken === "select") {
return [
{ value: "DISTINCT", detail: "Remove duplicate rows" },
{ value: "COUNT", detail: "Aggregate function" },
{ value: "SUM", detail: "Aggregate function" },
{ value: "AVG", detail: "Aggregate function" },
{ value: "MAX", detail: "Aggregate function" },
{ value: "MIN", detail: "Aggregate function" }
];
}
// FROM context - JOIN options and clauses
if (prevToken === "from" || currentToken === "from") {
return [
{ value: "JOIN", detail: "Inner join tables" },
{ value: "LEFT JOIN", detail: "Left outer join" },
{ value: "RIGHT JOIN", detail: "Right outer join" },
{ value: "FULL JOIN", detail: "Full outer join" },
{ value: "WHERE", detail: "Filter conditions" },
{ value: "GROUP BY", detail: "Group results" },
{ value: "ORDER BY", detail: "Sort results" }
];
}
// WHERE/HAVING context - logical operators
if (["where", "having", "on"].includes(prevToken || "") || ["where", "having", "on"].includes(currentToken || "")) {
return [
{ value: "AND", detail: "Logical AND operator" },
{ value: "OR", detail: "Logical OR operator" },
{ value: "NOT", detail: "Logical NOT operator" },
{ value: "IN", detail: "Match any value in list" },
{ value: "LIKE", detail: "Pattern matching" },
{ value: "BETWEEN", detail: "Range comparison" }
];
}
// Default context - general SQL keywords
return [
{ value: "SELECT", detail: "Query data" },
{ value: "FROM", detail: "Specify table" },
{ value: "WHERE", detail: "Filter conditions" },
{ value: "JOIN", detail: "Join tables" },
{ value: "GROUP BY", detail: "Group results" },
{ value: "ORDER BY", detail: "Sort results" },
{ value: "LIMIT", detail: "Limit results" }
];
}
//# sourceMappingURL=IntelliSenseApi.js.map
;