UNPKG

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
"use strict"; 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