LCOV - code coverage report
Current view: top level - dashql-app/src/session/scripts - script_format.ts Coverage Total Hit
Test: DashQL 915828b Lines: 96.9 % 96 93
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import * as dashql from '@ankoh/dashql-core';
       2              : 
       3              : import type { EditorView } from '@codemirror/view';
       4              : 
       5              : import type { ScriptData } from './session_scripts.js';
       6              : import type { AppSettings } from '../../config/app_config.js';
       7              : import { ConnectorType } from '../../connections/connector_info.js';
       8              : 
       9            1 : const DEFAULT_FORMAT_WIDTH = 80;
      10            1 : const DEFAULT_FORMAT_INDENTATION = 4;
      11            1 : const MIN_FORMAT_WIDTH = 24;
      12              : 
      13            1 : export function formattingDialectForConnector(connectorType?: ConnectorType): dashql.buffers.formatting.FormattingDialect {
      14            1 :     return connectorType === ConnectorType.TRINO
      15            1 :         ? dashql.buffers.formatting.FormattingDialect.TRINO
      16            1 :         : dashql.buffers.formatting.FormattingDialect.HYPER;
      17            1 : }
      18              : 
      19            1 : export function getKeywordCase(settings?: AppSettings): dashql.buffers.formatting.KeywordCase {
      20            1 :     return settings?.keywordCase === 'upper'
      21            1 :         ? dashql.buffers.formatting.KeywordCase.UPPER
      22            1 :         : dashql.buffers.formatting.KeywordCase.LOWER;
      23            1 : }
      24              : 
      25            1 : export function createScriptFormatConfig(
      26            1 :     mode: dashql.buffers.formatting.FormattingMode,
      27            1 :     debugMode: boolean = false,
      28            1 :     maxWidth: number = DEFAULT_FORMAT_WIDTH,
      29            1 :     keywordCase: dashql.buffers.formatting.KeywordCase = dashql.buffers.formatting.KeywordCase.LOWER,
      30            1 :     dialect: dashql.buffers.formatting.FormattingDialect = dashql.buffers.formatting.FormattingDialect.HYPER,
      31            1 : ): dashql.buffers.formatting.FormattingConfigT {
      32            1 :     return new dashql.buffers.formatting.FormattingConfigT(
      33            1 :         dialect,
      34            1 :         mode,
      35            1 :         maxWidth,
      36            1 :         DEFAULT_FORMAT_INDENTATION,
      37            1 :         debugMode,
      38            1 :         keywordCase,
      39            1 :     );
      40            1 : }
      41              : 
      42              : /// Format a SQL text in a throwaway script, null if the formatter cannot format all of it
      43            1 : export function formatSqlText(core: dashql.DashQL, text: string, config: dashql.buffers.formatting.FormattingConfigT): string | null {
      44            1 :     const catalog = core.createCatalog();
      45            1 :     const script = core.createScript(catalog);
      46            1 :     let formatted: dashql.DashQLScript | null = null;
      47            1 :     try {
      48            1 :         script.insertTextAt(0, text);
      49            1 :         if (!script.isFullyFormattable(config)) return null;
      50            1 :         formatted = script.format(config);
      51            1 :         return formatted.toString();
      52            1 :     } catch {
      53            0 :         return null;
      54            1 :     } finally {
      55            1 :         formatted?.destroy();
      56            1 :         script.destroy();
      57            1 :         catalog.destroy();
      58            1 :     }
      59            1 : }
      60              : 
      61            1 : export function measureScriptFormatWidth(editorView: Pick<EditorView, 'defaultCharacterWidth' | 'scrollDOM'>): number {
      62            1 :     const charWidth = editorView.defaultCharacterWidth;
      63            1 :     const availableWidth = editorView.scrollDOM.clientWidth;
      64            1 :     if (!(charWidth > 0) || !(availableWidth > 0)) {
      65            0 :         return DEFAULT_FORMAT_WIDTH;
      66              :     }
      67            1 :     return Math.max(MIN_FORMAT_WIDTH, Math.floor(availableWidth / charWidth));
      68            1 : }
      69              : 
      70            1 : export function isScriptFormattable(
      71            1 :     scriptData: ScriptData | null,
      72            1 :     dialect: dashql.buffers.formatting.FormattingDialect = dashql.buffers.formatting.FormattingDialect.HYPER,
      73            1 : ): boolean {
      74            1 :     if (scriptData == null) return false;
      75            1 :     try {
      76            1 :         return scriptData.scriptSession.isFullyFormattable(
      77            1 :             createScriptFormatConfig(dashql.buffers.formatting.FormattingMode.PRETTY, false, DEFAULT_FORMAT_WIDTH,
      78            1 :                 dashql.buffers.formatting.KeywordCase.LOWER, dialect),
      79            1 :             true,
      80            1 :         );
      81            1 :     } catch {
      82            1 :         return false;
      83            1 :     }
      84            1 : }
      85              : 
      86            1 : export function formatScriptEditor(
      87            1 :     editorView: EditorView | null,
      88            1 :     scriptData: ScriptData | null,
      89            1 :     mode: dashql.buffers.formatting.FormattingMode,
      90            1 :     onFormattedText: (text: string) => void,
      91            1 :     debugMode: boolean = false,
      92            1 :     keywordCase: dashql.buffers.formatting.KeywordCase = dashql.buffers.formatting.KeywordCase.LOWER,
      93            1 :     dialect: dashql.buffers.formatting.FormattingDialect = dashql.buffers.formatting.FormattingDialect.HYPER,
      94            1 : ): boolean {
      95            1 :     if (editorView == null || scriptData == null) return false;
      96              : 
      97            1 :     let formattedScript: dashql.DashQLScript | null = null;
      98            1 :     try {
      99            1 :         const maxWidth = measureScriptFormatWidth(editorView);
     100            1 :         formattedScript = scriptData.scriptSession.format(
     101            1 :             createScriptFormatConfig(mode, debugMode, maxWidth, keywordCase, dialect),
     102            1 :             null,
     103            1 :         );
     104            1 :         const formattedText = formattedScript.toString();
     105            1 :         if (formattedText === editorView.state.doc.toString()) return false;
     106            1 :         onFormattedText(formattedText);
     107            1 :         editorView.focus();
     108            1 :         return true;
     109            1 :     } catch {
     110            0 :         return false;
     111            1 :     } finally {
     112            1 :         formattedScript?.destroy();
     113            1 :     }
     114            1 : }
        

Generated by: LCOV version 2.0-1