1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- 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']]);
|