mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-10-30 14:49:14 +00:00
99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
import {StringAccumulator} from 'sentry/views/starfish/utils/sqlish/formatters/stringAccumulator';
|
|
import type {Token} from 'sentry/views/starfish/utils/sqlish/types';
|
|
|
|
interface Options {
|
|
maxLineLength?: number;
|
|
}
|
|
|
|
export function string(tokens: Token[], options: Options = {}): string {
|
|
const accumulator = new StringAccumulator();
|
|
|
|
let precedingNonWhitespaceToken: Token | undefined = undefined;
|
|
let parenthesisLevel: number = 0; // Tracks the current parenthesis nesting level
|
|
const indentationLevels: number[] = []; // Tracks the parenthesis nesting levels at which we've incremented the indentation
|
|
|
|
function contentize(token: Token): void {
|
|
if (Array.isArray(token.content)) {
|
|
token.content.forEach(contentize);
|
|
return;
|
|
}
|
|
|
|
if (token.type === 'LeftParenthesis') {
|
|
parenthesisLevel += 1;
|
|
accumulator.add('(');
|
|
|
|
// If the previous legible token is a meaningful keyword that triggers a
|
|
// newline, increase the current indentation level and note the parenthesis level where this happened
|
|
if (
|
|
typeof precedingNonWhitespaceToken?.content === 'string' &&
|
|
PARENTHESIS_NEWLINE_KEYWORDS.has(precedingNonWhitespaceToken.content)
|
|
) {
|
|
accumulator.break();
|
|
|
|
accumulator.indent();
|
|
indentationLevels.push(parenthesisLevel);
|
|
}
|
|
}
|
|
|
|
if (token.type === 'RightParenthesis') {
|
|
// If this right parenthesis closes a left parenthesis at a level where
|
|
// we incremented the indentation, decrement the indentation
|
|
if (indentationLevels.at(-1) === parenthesisLevel) {
|
|
accumulator.break();
|
|
accumulator.unindent();
|
|
indentationLevels.pop();
|
|
}
|
|
|
|
parenthesisLevel -= 1;
|
|
accumulator.add(')');
|
|
}
|
|
|
|
if (typeof token.content === 'string') {
|
|
if (token.type === 'Keyword' && NEWLINE_KEYWORDS.has(token.content)) {
|
|
if (!accumulator.lastLine.isEmpty) {
|
|
accumulator.break();
|
|
}
|
|
|
|
accumulator.add(token.content);
|
|
} else if (token.type === 'Whitespace') {
|
|
// Convert all whitespace to single spaces
|
|
accumulator.space();
|
|
} else if (['LeftParenthesis', 'RightParenthesis'].includes(token.type)) {
|
|
// Parenthesis contents are appended above, so we can skip them here
|
|
} else {
|
|
accumulator.add(token.content);
|
|
}
|
|
}
|
|
|
|
if (token.type !== 'Whitespace') {
|
|
precedingNonWhitespaceToken = token;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
tokens.forEach(contentize);
|
|
return accumulator.toString(options.maxLineLength);
|
|
}
|
|
|
|
// Keywords that always trigger a newline
|
|
const NEWLINE_KEYWORDS = new Set([
|
|
'DELETE',
|
|
'FROM',
|
|
'GROUP',
|
|
'INNER',
|
|
'INSERT',
|
|
'LEFT',
|
|
'LIMIT',
|
|
'OFFSET',
|
|
'ORDER',
|
|
'RETURNING',
|
|
'RIGHT',
|
|
'SELECT',
|
|
'VALUES',
|
|
'WHERE',
|
|
]);
|
|
|
|
// Keywords that may or may not trigger a newline, but they always trigger a newlines if followed by a parenthesis
|
|
const PARENTHESIS_NEWLINE_KEYWORDS = new Set([...NEWLINE_KEYWORDS, ...['IN']]);
|