rawsql-ts
Version:
[beta]High-performance SQL parser and AST analyzer written in TypeScript. Provides fast parsing and advanced transformation capabilities.
306 lines • 13.3 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.CommentEditor = void 0;
const SqlComponent_1 = require("../models/SqlComponent");
/**
* Utility class for editing comments on SQL components.
* Provides functions to add, edit, delete, and search comments in SQL AST.
*/
class CommentEditor {
/**
* Add a comment to a SQL component
* For SelectQuery components, adds to headerComments for query-level comments
* @param component The SQL component to add comment to
* @param comment The comment text to add
*/
static addComment(component, comment) {
// Check if this is a SelectQuery component - add to headerComments for query-level comments
if (this.isSelectQuery(component)) {
const selectQuery = component;
if (!selectQuery.headerComments) {
selectQuery.headerComments = [];
}
selectQuery.headerComments.push(comment);
}
else {
// For other components, add to regular comments
if (!component.comments) {
component.comments = [];
}
component.comments.push(comment);
}
}
/**
* Check if a component implements SelectQuery interface
* Uses discriminator property for robust type detection
* @param component The component to check
* @returns true if the component is a SelectQuery
*/
static isSelectQuery(component) {
// Use discriminator property for robust type detection
return '__selectQueryType' in component &&
component.__selectQueryType === 'SelectQuery';
}
/**
* Edit an existing comment by index
* For SelectQuery components, edits headerComments
* @param component The SQL component containing the comment
* @param index The index of the comment to edit (0-based)
* @param newComment The new comment text
* @throws Error if index is invalid
*/
static editComment(component, index, newComment) {
var _a, _b;
if (this.isSelectQuery(component)) {
const selectQuery = component;
if (!selectQuery.headerComments || index < 0 || index >= selectQuery.headerComments.length) {
throw new Error(`Invalid comment index: ${index}. Component has ${((_a = selectQuery.headerComments) === null || _a === void 0 ? void 0 : _a.length) || 0} comments.`);
}
selectQuery.headerComments[index] = newComment;
}
else {
if (!component.comments || index < 0 || index >= component.comments.length) {
throw new Error(`Invalid comment index: ${index}. Component has ${((_b = component.comments) === null || _b === void 0 ? void 0 : _b.length) || 0} comments.`);
}
component.comments[index] = newComment;
}
}
/**
* Delete a comment by index
* For SelectQuery components, deletes from headerComments
* @param component The SQL component containing the comment
* @param index The index of the comment to delete (0-based)
* @throws Error if index is invalid
*/
static deleteComment(component, index) {
var _a, _b;
if (this.isSelectQuery(component)) {
const selectQuery = component;
if (!selectQuery.headerComments || index < 0 || index >= selectQuery.headerComments.length) {
throw new Error(`Invalid comment index: ${index}. Component has ${((_a = selectQuery.headerComments) === null || _a === void 0 ? void 0 : _a.length) || 0} comments.`);
}
selectQuery.headerComments.splice(index, 1);
if (selectQuery.headerComments.length === 0) {
selectQuery.headerComments = null;
}
}
else {
if (!component.comments || index < 0 || index >= component.comments.length) {
throw new Error(`Invalid comment index: ${index}. Component has ${((_b = component.comments) === null || _b === void 0 ? void 0 : _b.length) || 0} comments.`);
}
component.comments.splice(index, 1);
if (component.comments.length === 0) {
component.comments = null;
}
}
}
/**
* Delete all comments from a component
* @param component The SQL component to clear comments from
*/
static deleteAllComments(component) {
if (this.isSelectQuery(component)) {
const selectQuery = component;
selectQuery.headerComments = null;
}
else {
component.comments = null;
}
}
/**
* Get all comments from a component
* For SelectQuery components, returns headerComments instead of regular comments
* @param component The SQL component to get comments from
* @returns Array of comment strings (empty array if no comments)
*/
static getComments(component) {
if (this.isSelectQuery(component)) {
const selectQuery = component;
return selectQuery.headerComments || [];
}
return component.comments || [];
}
/**
* Find all components in the AST that have comments containing the search text
* @param root The root SQL component to search from
* @param searchText The text to search for in comments
* @param caseSensitive Whether the search should be case-sensitive (default: false)
* @returns Array of components that have matching comments
*/
static findComponentsWithComment(root, searchText, caseSensitive = false) {
const results = [];
const searchTerm = caseSensitive ? searchText : searchText.toLowerCase();
const traverse = (component) => {
if (component && component instanceof SqlComponent_1.SqlComponent) {
let hasMatchingComment = false;
// Check regular comments
if (component.comments && component.comments.some(c => {
const commentText = caseSensitive ? c : c.toLowerCase();
return commentText.includes(searchTerm);
})) {
hasMatchingComment = true;
}
// Check headerComments for SelectQuery components
if (this.isSelectQuery(component)) {
const selectQuery = component;
if (selectQuery.headerComments && selectQuery.headerComments.some(c => {
const commentText = caseSensitive ? c : c.toLowerCase();
return commentText.includes(searchTerm);
})) {
hasMatchingComment = true;
}
}
if (hasMatchingComment) {
results.push(component);
}
}
// Traverse all properties recursively
for (const key in component) {
if (component[key] && typeof component[key] === 'object') {
if (Array.isArray(component[key])) {
component[key].forEach(traverse);
}
else {
traverse(component[key]);
}
}
}
};
traverse(root);
return results;
}
/**
* Replace all occurrences of a text in comments across the entire AST
* @param root The root SQL component to search and replace in
* @param searchText The text to search for
* @param replaceText The text to replace with
* @param caseSensitive Whether the search should be case-sensitive (default: false)
* @returns Number of replacements made
*/
static replaceInComments(root, searchText, replaceText, caseSensitive = false) {
let replacementCount = 0;
const traverse = (component) => {
if (component && component instanceof SqlComponent_1.SqlComponent) {
// Handle regular comments
if (component.comments) {
for (let i = 0; i < component.comments.length; i++) {
const originalComment = component.comments[i];
const flags = caseSensitive ? 'g' : 'gi';
const regex = new RegExp(searchText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), flags);
const newComment = originalComment.replace(regex, replaceText);
if (newComment !== originalComment) {
component.comments[i] = newComment;
replacementCount++;
}
}
}
// Handle headerComments for SelectQuery components
if (this.isSelectQuery(component)) {
const selectQuery = component;
if (selectQuery.headerComments) {
for (let i = 0; i < selectQuery.headerComments.length; i++) {
const originalComment = selectQuery.headerComments[i];
const flags = caseSensitive ? 'g' : 'gi';
const regex = new RegExp(searchText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), flags);
const newComment = originalComment.replace(regex, replaceText);
if (newComment !== originalComment) {
selectQuery.headerComments[i] = newComment;
replacementCount++;
}
}
}
}
}
// Traverse all properties recursively
for (const key in component) {
if (component[key] && typeof component[key] === 'object') {
if (Array.isArray(component[key])) {
component[key].forEach(traverse);
}
else {
traverse(component[key]);
}
}
}
};
traverse(root);
return replacementCount;
}
/**
* Count total number of comments in the AST
* @param root The root SQL component to count comments in
* @returns Total number of comments
*/
static countComments(root) {
let count = 0;
const traverse = (component) => {
if (component && component instanceof SqlComponent_1.SqlComponent) {
if (component.comments) {
count += component.comments.length;
}
// Count headerComments for SelectQuery components
if (this.isSelectQuery(component)) {
const selectQuery = component;
if (selectQuery.headerComments) {
count += selectQuery.headerComments.length;
}
}
}
// Traverse all properties recursively
for (const key in component) {
if (component[key] && typeof component[key] === 'object') {
if (Array.isArray(component[key])) {
component[key].forEach(traverse);
}
else {
traverse(component[key]);
}
}
}
};
traverse(root);
return count;
}
/**
* Get all comments from the entire AST as a flat array with their source components
* @param root The root SQL component to extract comments from
* @returns Array of objects containing comment text and the component they belong to
*/
static getAllComments(root) {
const results = [];
const traverse = (component) => {
if (component && component instanceof SqlComponent_1.SqlComponent) {
// Add regular comments
if (component.comments) {
component.comments.forEach((comment, index) => {
results.push({ comment, component, index });
});
}
// Add headerComments for SelectQuery components
if (this.isSelectQuery(component)) {
const selectQuery = component;
if (selectQuery.headerComments) {
selectQuery.headerComments.forEach((comment, index) => {
results.push({ comment, component, index });
});
}
}
}
// Traverse all properties recursively
for (const key in component) {
if (component[key] && typeof component[key] === 'object') {
if (Array.isArray(component[key])) {
component[key].forEach(traverse);
}
else {
traverse(component[key]);
}
}
}
};
traverse(root);
return results;
}
}
exports.CommentEditor = CommentEditor;
//# sourceMappingURL=CommentEditor.js.map
;