mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 10:28:44 +00:00
feat(sql-formatter): add setting to preserve blank lines
This commit is contained in:
@@ -109,6 +109,7 @@ const sqlFormatterOptionLabelKeys: Record<keyof SqlFormatterOptionSettings, stri
|
||||
fromClauseLayout: "settings.sqlFormatterFromClauseLayout",
|
||||
expressionWidth: "settings.sqlFormatterExpressionWidth",
|
||||
linesBetweenQueries: "settings.sqlFormatterLinesBetweenQueries",
|
||||
preserveEmptyLines: "settings.sqlFormatterPreserveEmptyLines",
|
||||
denseOperators: "settings.sqlFormatterDenseOperators",
|
||||
newlineBeforeSemicolon: "settings.sqlFormatterNewlineBeforeSemicolon",
|
||||
paramTypes: "settings.sqlFormatterParamTypes",
|
||||
@@ -667,6 +668,11 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
|
||||
<div class="grid gap-3 md:grid-cols-2">
|
||||
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
|
||||
<Label for="sql-formatter-preserve-empty-lines">{{ t("settings.sqlFormatterPreserveEmptyLines") }}</Label>
|
||||
<Switch id="sql-formatter-preserve-empty-lines" :model-value="settings.preserveEmptyLines" @update:model-value="(value: boolean) => updateOption('preserveEmptyLines', value)" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between gap-4 rounded-md border bg-muted/20 px-3 py-2">
|
||||
<Label for="sql-formatter-dense-operators">{{ t("settings.sqlFormatterDenseOperators") }}</Label>
|
||||
<Switch id="sql-formatter-dense-operators" :model-value="settings.denseOperators" @update:model-value="(value: boolean) => updateOption('denseOperators', value)" />
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useToast } from "@/composables/useToast";
|
||||
import { copyToClipboard } from "@/lib/common/clipboard";
|
||||
import { formatSqlText, type SqlFormatDialect } from "@/lib/sql/sqlFormatter";
|
||||
import { createShikiSqlHighlighter, type SqlHighlighter } from "@/lib/sql/sqlHighlighter";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
|
||||
const props = defineProps<{
|
||||
sql: string;
|
||||
@@ -27,6 +28,7 @@ const emit = defineEmits<{
|
||||
const { t } = useI18n();
|
||||
const { isDark } = useTheme();
|
||||
const { toast } = useToast();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
const isFormatted = ref(false);
|
||||
const formattedSql = ref("");
|
||||
@@ -79,7 +81,7 @@ async function toggleFormat() {
|
||||
|
||||
formatting.value = true;
|
||||
try {
|
||||
formattedSql.value = await formatSqlText(props.sql, props.sqlFormatDialect ?? "generic");
|
||||
formattedSql.value = await formatSqlText(props.sql, props.sqlFormatDialect ?? "generic", settingsStore.editorSettings.sqlFormatter);
|
||||
isFormatted.value = true;
|
||||
await highlightSql();
|
||||
} catch {
|
||||
|
||||
@@ -6057,6 +6057,7 @@ export default {
|
||||
sqlFormatterFromSameLine: "FROM with first table",
|
||||
sqlFormatterExpressionWidth: "Expression width",
|
||||
sqlFormatterLinesBetweenQueries: "Lines between queries",
|
||||
sqlFormatterPreserveEmptyLines: "Preserve empty lines",
|
||||
sqlFormatterDenseOperators: "Dense operators",
|
||||
sqlFormatterNewlineBeforeSemicolon: "Semicolon on new line",
|
||||
sqlFormatterAdvancedOptions: "Advanced options",
|
||||
|
||||
@@ -5786,6 +5786,7 @@ export default withEnglishFallback({
|
||||
sqlFormatterFromSameLine: "FROM con la primera tabla",
|
||||
sqlFormatterExpressionWidth: "Ancho de expresión",
|
||||
sqlFormatterLinesBetweenQueries: "Líneas entre consultas",
|
||||
sqlFormatterPreserveEmptyLines: "Conservar líneas vacías",
|
||||
sqlFormatterDenseOperators: "Operadores compactos",
|
||||
sqlFormatterNewlineBeforeSemicolon: "Punto y coma en nueva línea",
|
||||
sqlFormatterAdvancedOptions: "Opciones avanzadas",
|
||||
|
||||
@@ -5786,6 +5786,7 @@ export default withEnglishFallback({
|
||||
sqlFormatterFromSameLine: "FROM con la prima tabella",
|
||||
sqlFormatterExpressionWidth: "Larghezza espressione",
|
||||
sqlFormatterLinesBetweenQueries: "Righe tra query",
|
||||
sqlFormatterPreserveEmptyLines: "Mantieni le righe vuote",
|
||||
sqlFormatterDenseOperators: "Operatori compatti",
|
||||
sqlFormatterNewlineBeforeSemicolon: "Punto e virgola su nuova riga",
|
||||
sqlFormatterAdvancedOptions: "Opzioni avanzate",
|
||||
|
||||
@@ -5824,6 +5824,7 @@ export default withEnglishFallback({
|
||||
sqlFormatterFromSameLine: "FROM と最初のテーブルを同じ行に配置",
|
||||
sqlFormatterExpressionWidth: "式の幅",
|
||||
sqlFormatterLinesBetweenQueries: "クエリ間の行数",
|
||||
sqlFormatterPreserveEmptyLines: "空行を保持",
|
||||
sqlFormatterDenseOperators: "演算子を詰める",
|
||||
sqlFormatterNewlineBeforeSemicolon: "セミコロンを新しい行に",
|
||||
sqlFormatterAdvancedOptions: "詳細オプション",
|
||||
|
||||
@@ -5465,6 +5465,7 @@ export default withEnglishFallback({
|
||||
sqlFormatterFromSameLine: "FROM과 첫 번째 테이블을 같은 줄에 배치",
|
||||
sqlFormatterExpressionWidth: "표현식 너비",
|
||||
sqlFormatterLinesBetweenQueries: "쿼리 사이 줄 수",
|
||||
sqlFormatterPreserveEmptyLines: "빈 줄 유지",
|
||||
sqlFormatterDenseOperators: "조밀한 연산자",
|
||||
sqlFormatterNewlineBeforeSemicolon: "세미콜론 새 줄에",
|
||||
sqlFormatterAdvancedOptions: "고급 옵션",
|
||||
|
||||
@@ -5788,6 +5788,7 @@ export default withEnglishFallback({
|
||||
sqlFormatterFromSameLine: "FROM com a primeira tabela",
|
||||
sqlFormatterExpressionWidth: "Largura da expressão",
|
||||
sqlFormatterLinesBetweenQueries: "Linhas entre consultas",
|
||||
sqlFormatterPreserveEmptyLines: "Preservar linhas em branco",
|
||||
sqlFormatterDenseOperators: "Operadores compactos",
|
||||
sqlFormatterNewlineBeforeSemicolon: "Ponto e vírgula em nova linha",
|
||||
sqlFormatterAdvancedOptions: "Opções avançadas",
|
||||
|
||||
@@ -6041,6 +6041,7 @@ export default withEnglishFallback({
|
||||
sqlFormatterFromSameLine: "FROM 与首个表同行",
|
||||
sqlFormatterExpressionWidth: "表达式宽度",
|
||||
sqlFormatterLinesBetweenQueries: "查询之间空行",
|
||||
sqlFormatterPreserveEmptyLines: "保留原有空行",
|
||||
sqlFormatterDenseOperators: "紧凑运算符",
|
||||
sqlFormatterNewlineBeforeSemicolon: "分号单独换行",
|
||||
sqlFormatterAdvancedOptions: "高级选项",
|
||||
|
||||
@@ -5110,6 +5110,7 @@ export default withEnglishFallback({
|
||||
sqlFormatterFromSameLine: "FROM 與第一個表同行",
|
||||
sqlFormatterExpressionWidth: "運算式寬度",
|
||||
sqlFormatterLinesBetweenQueries: "查詢之間空行",
|
||||
sqlFormatterPreserveEmptyLines: "保留原有空行",
|
||||
sqlFormatterDenseOperators: "緊湊運算子",
|
||||
sqlFormatterNewlineBeforeSemicolon: "分號獨立換行",
|
||||
sqlFormatterAdvancedOptions: "進階選項",
|
||||
|
||||
@@ -16,6 +16,30 @@ describe("sqlFormatter", () => {
|
||||
expect(canFormatSqlForDatabaseType("mysql")).toBe(true);
|
||||
});
|
||||
|
||||
it("preserves source empty lines only when configured", async () => {
|
||||
const sql = "-- tstt\n\nSELECT * FROM AUX_TABLE AS au LIMIT 100;";
|
||||
const consecutiveEmptyLines = "-- section\n\n\nSELECT 1;";
|
||||
const queriesWithEmptyLine = "SELECT 1;\n\nSELECT 2;";
|
||||
const queriesWithTwoEmptyLines = "SELECT 1;\n\n\nSELECT 2;";
|
||||
|
||||
const defaultFormatted = await formatSqlForEditing(sql, "generic");
|
||||
const preserved = await formatSqlForEditing(sql, "generic", { preserveEmptyLines: true });
|
||||
const preservedConsecutive = await formatSqlForEditing(consecutiveEmptyLines, "generic", { preserveEmptyLines: true });
|
||||
const preservedQueriesNoSpacing = await formatSqlForEditing(queriesWithEmptyLine, "generic", { preserveEmptyLines: true, linesBetweenQueries: 0 });
|
||||
const preservedQueries = await formatSqlForEditing(queriesWithEmptyLine, "generic", { preserveEmptyLines: true, linesBetweenQueries: 1 });
|
||||
const preservedQueriesWideSpacing = await formatSqlForEditing(queriesWithEmptyLine, "generic", { preserveEmptyLines: true, linesBetweenQueries: 2 });
|
||||
const preservedQueriesWithTwoEmptyLines = await formatSqlForEditing(queriesWithTwoEmptyLines, "generic", { preserveEmptyLines: true, linesBetweenQueries: 1 });
|
||||
|
||||
expect(defaultFormatted).toContain("-- tstt\nSELECT");
|
||||
expect(preserved).toContain("-- tstt\n\nSELECT");
|
||||
expect(preservedConsecutive).toContain("-- section\n\n\nSELECT");
|
||||
expect(preservedQueriesNoSpacing).toBe("SELECT\n 1;\n\nSELECT\n 2;");
|
||||
expect(preservedQueries).toBe("SELECT\n 1;\n\nSELECT\n 2;");
|
||||
expect(preservedQueriesWideSpacing).toBe("SELECT\n 1;\n\n\nSELECT\n 2;");
|
||||
expect(preservedQueriesWithTwoEmptyLines).toBe("SELECT\n 1;\n\n\nSELECT\n 2;");
|
||||
expect(preserved).not.toContain("__DBX_PRESERVE_EMPTY_LINE_");
|
||||
});
|
||||
|
||||
it("maps PostgreSQL-compatible database types to the postgres formatter dialect", () => {
|
||||
for (const dbType of ["postgres", "kwdb", "gaussdb", "opengauss", "questdb", "kingbase", "highgo", "vastbase", "redshift"]) {
|
||||
expect(sqlFormatDialectForDbType(dbType)).toBe("postgres");
|
||||
|
||||
@@ -63,4 +63,13 @@ describe("sqlFormatterConfig shortcut storage", () => {
|
||||
if (result.ok) expect(result.settings.fromClauseLayout).toBe("sameLine");
|
||||
expect(JSON.parse(serializeSqlFormatterConfig({ fromClauseLayout: "sameLine" })).options.fromClauseLayout).toBe("sameLine");
|
||||
});
|
||||
|
||||
it("defaults empty-line preservation off and serializes an explicit opt-in", () => {
|
||||
const defaultConfig = JSON.parse(serializeSqlFormatterConfig({}));
|
||||
const optIn = parseSqlFormatterConfig(JSON.stringify({ version: 1, formatter: "sql-formatter", options: { preserveEmptyLines: true } }));
|
||||
|
||||
expect(defaultConfig.options.preserveEmptyLines).toBe(false);
|
||||
expect(optIn).toEqual(expect.objectContaining({ ok: true }));
|
||||
if (optIn.ok) expect(optIn.settings.preserveEmptyLines).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -239,6 +239,7 @@ describe("settings search", () => {
|
||||
{ titleKey: "settings.sqlFormatterLogicalOperatorNewline", category: "formatter", targetId: "formatter" },
|
||||
{ titleKey: "settings.sqlFormatterExpressionWidth", category: "formatter", targetId: "formatter" },
|
||||
{ titleKey: "settings.sqlFormatterLinesBetweenQueries", category: "formatter", targetId: "formatter" },
|
||||
{ titleKey: "settings.sqlFormatterPreserveEmptyLines", category: "formatter", targetId: "formatter" },
|
||||
{ titleKey: "settings.sqlFormatterDenseOperators", category: "formatter", targetId: "formatter" },
|
||||
{ titleKey: "settings.sqlFormatterNewlineBeforeSemicolon", category: "formatter", targetId: "formatter" },
|
||||
{ titleKey: "settings.sqlFormatterParamTypes", category: "formatter", targetId: "formatter" },
|
||||
|
||||
@@ -142,6 +142,7 @@ export const SETTINGS_SEARCH_DEFINITIONS: readonly SettingsSearchDefinition[] =
|
||||
{ id: "formatter-from-clause-layout", category: "formatter", titleKey: "settings.sqlFormatterFromClauseLayout", targetId: "formatter" },
|
||||
{ id: "formatter-expression-width", category: "formatter", titleKey: "settings.sqlFormatterExpressionWidth", targetId: "formatter" },
|
||||
{ id: "formatter-lines-between-queries", category: "formatter", titleKey: "settings.sqlFormatterLinesBetweenQueries", targetId: "formatter" },
|
||||
{ id: "formatter-preserve-empty-lines", category: "formatter", titleKey: "settings.sqlFormatterPreserveEmptyLines", targetId: "formatter" },
|
||||
{ id: "formatter-dense-operators", category: "formatter", titleKey: "settings.sqlFormatterDenseOperators", targetId: "formatter" },
|
||||
{ id: "formatter-newline-before-semicolon", category: "formatter", titleKey: "settings.sqlFormatterNewlineBeforeSemicolon", targetId: "formatter" },
|
||||
{ id: "formatter-param-types", category: "formatter", titleKey: "settings.sqlFormatterParamTypes", targetId: "formatter" },
|
||||
|
||||
@@ -118,6 +118,95 @@ function splitTrailingStandaloneDot(sql: string): { body: string; suffix: string
|
||||
};
|
||||
}
|
||||
|
||||
interface EmptyLineProtection {
|
||||
sql: string;
|
||||
markers: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces blank source lines with unique line comments while the third-party
|
||||
* formatter runs. sql-formatter intentionally normalizes whitespace, whereas
|
||||
* the optional DBX setting needs to retain visual paragraph boundaries such as
|
||||
* the blank line between a heading comment and a query. Line comments are
|
||||
* valid at every SQL code boundary and are restored only after all DBX layout
|
||||
* post-processing is complete.
|
||||
*/
|
||||
function protectEmptyLines(sql: string): EmptyLineProtection {
|
||||
let namespace = 0;
|
||||
while (sql.includes(`__DBX_PRESERVE_EMPTY_LINE_${namespace}_`)) namespace += 1;
|
||||
|
||||
const markers: string[] = [];
|
||||
const lineBreakPattern = /\r\n|\r|\n/g;
|
||||
let output = "";
|
||||
let lineStart = 0;
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
while ((match = lineBreakPattern.exec(sql))) {
|
||||
const line = sql.slice(lineStart, match.index);
|
||||
if (line.trim().length === 0) {
|
||||
const marker = `-- __DBX_PRESERVE_EMPTY_LINE_${namespace}_${markers.length}__`;
|
||||
markers.push(marker);
|
||||
output += marker;
|
||||
} else {
|
||||
output += line;
|
||||
}
|
||||
output += match[0];
|
||||
lineStart = lineBreakPattern.lastIndex;
|
||||
}
|
||||
|
||||
// A final non-terminated blank line is still a user-authored empty line.
|
||||
// Do not manufacture one after a trailing line break, though: that would
|
||||
// turn the normal EOF sentinel into an additional preserved blank line.
|
||||
const finalLine = sql.slice(lineStart);
|
||||
if (finalLine.length > 0 && finalLine.trim().length === 0) {
|
||||
const marker = `-- __DBX_PRESERVE_EMPTY_LINE_${namespace}_${markers.length}__`;
|
||||
markers.push(marker);
|
||||
output += marker;
|
||||
} else {
|
||||
output += finalLine;
|
||||
}
|
||||
|
||||
return { sql: markers.length > 0 ? output : sql, markers };
|
||||
}
|
||||
|
||||
function restoreProtectedEmptyLines(sql: string, markers: readonly string[]): string {
|
||||
if (markers.length === 0) return sql;
|
||||
|
||||
const markerSet = new Set(markers);
|
||||
const lines = sql.split(/\r\n|\r|\n/);
|
||||
for (let index = 0; index < lines.length; ) {
|
||||
if (!markerSet.has(lines[index].trim())) {
|
||||
index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
let runEnd = index;
|
||||
while (runEnd < lines.length && markerSet.has(lines[runEnd].trim())) runEnd += 1;
|
||||
const markerCount = runEnd - index;
|
||||
|
||||
// sql-formatter adds `linesBetweenQueries` blank lines before a marker
|
||||
// group placed between statements. Those lines did not exist in the
|
||||
// source—the marker group itself represents the source blank lines—so
|
||||
// remove at most one generated line per original blank line. This keeps
|
||||
// the larger of the user-authored spacing and the formatter's configured
|
||||
// query spacing instead of adding the two counts together.
|
||||
let removed = 0;
|
||||
while (removed < markerCount && index > 0 && lines[index - 1].trim().length === 0) {
|
||||
lines.splice(index - 1, 1);
|
||||
index -= 1;
|
||||
runEnd -= 1;
|
||||
removed += 1;
|
||||
}
|
||||
|
||||
for (let markerIndex = index; markerIndex < runEnd; markerIndex += 1) {
|
||||
lines[markerIndex] = "";
|
||||
}
|
||||
index = runEnd;
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
const DUCKDB_ALIAS_IDENTIFIER_START_RE = /[\p{L}_]/u;
|
||||
const DUCKDB_ALIAS_IDENTIFIER_CHAR_RE = /[\p{L}\p{N}_]/u;
|
||||
|
||||
@@ -253,7 +342,9 @@ export async function formatSqlText(sql: string, dialect: SqlFormatDialect = "ge
|
||||
const normalizedSettings = normalizeSqlFormatterSettings(settings);
|
||||
const options = sqlFormatterOptions(normalizedSettings);
|
||||
const language = formatterLanguage(dialect);
|
||||
const protectedInput = dialect === "duckdb" ? protectDuckDbPrefixAliasSeparators(sql) : { sql, marker: null };
|
||||
const emptyLineProtection = normalizedSettings.preserveEmptyLines ? protectEmptyLines(sql) : null;
|
||||
const sqlWithProtectedEmptyLines = emptyLineProtection?.sql ?? sql;
|
||||
const protectedInput = dialect === "duckdb" ? protectDuckDbPrefixAliasSeparators(sqlWithProtectedEmptyLines) : { sql: sqlWithProtectedEmptyLines, marker: null };
|
||||
const formatterOptions =
|
||||
language === "postgresql"
|
||||
? {
|
||||
@@ -290,16 +381,20 @@ export async function formatSqlText(sql: string, dialect: SqlFormatDialect = "ge
|
||||
}
|
||||
};
|
||||
|
||||
const finalizeFormattedSql = (formatted: string): string => {
|
||||
const restoredDuckDbAliases = restoreDuckDbPrefixAliasSeparators(formatted, protectedInput.marker);
|
||||
const laidOut = applySqlFormatterLayout(restoredDuckDbAliases, normalizedSettings, dialect);
|
||||
return emptyLineProtection ? restoreProtectedEmptyLines(laidOut, emptyLineProtection.markers) : laidOut;
|
||||
};
|
||||
|
||||
try {
|
||||
const formatted = restoreDuckDbPrefixAliasSeparators(formatWithFallback(protectedInput.sql), protectedInput.marker);
|
||||
return applySqlFormatterLayout(formatted, normalizedSettings, dialect);
|
||||
return finalizeFormattedSql(formatWithFallback(protectedInput.sql));
|
||||
} catch (err) {
|
||||
const trailingDot = dialect === "dameng" ? splitTrailingStandaloneDot(sql) : null;
|
||||
const trailingDot = dialect === "dameng" ? splitTrailingStandaloneDot(protectedInput.sql) : null;
|
||||
if (!trailingDot) throw err;
|
||||
|
||||
try {
|
||||
const formatted = applySqlFormatterLayout(formatWithFallback(trailingDot.body), normalizedSettings, dialect);
|
||||
return `${formatted}${trailingDot.suffix}`;
|
||||
return finalizeFormattedSql(`${formatWithFallback(trailingDot.body)}${trailingDot.suffix}`);
|
||||
} catch {
|
||||
throw err;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ export interface SqlFormatterOptionSettings {
|
||||
fromClauseLayout: SqlFormatterFromClauseLayout;
|
||||
expressionWidth: SqlFormatterExpressionWidth;
|
||||
linesBetweenQueries: SqlFormatterLinesBetweenQueries;
|
||||
preserveEmptyLines: boolean;
|
||||
denseOperators: boolean;
|
||||
newlineBeforeSemicolon: boolean;
|
||||
paramTypes: SqlFormatterParamTypes | null;
|
||||
@@ -76,6 +77,7 @@ export const DEFAULT_SQL_FORMATTER_SETTINGS: SqlFormatterSettings = {
|
||||
fromClauseLayout: "newLine",
|
||||
expressionWidth: 50,
|
||||
linesBetweenQueries: 1,
|
||||
preserveEmptyLines: false,
|
||||
denseOperators: false,
|
||||
newlineBeforeSemicolon: false,
|
||||
paramTypes: null,
|
||||
@@ -93,6 +95,7 @@ const SQL_FORMATTER_OPTION_KEYS = new Set<keyof SqlFormatterOptionSettings>([
|
||||
"fromClauseLayout",
|
||||
"expressionWidth",
|
||||
"linesBetweenQueries",
|
||||
"preserveEmptyLines",
|
||||
"denseOperators",
|
||||
"newlineBeforeSemicolon",
|
||||
"paramTypes",
|
||||
@@ -110,6 +113,7 @@ const SQL_FORMATTER_OPTION_VALIDATORS: Record<keyof SqlFormatterOptionSettings,
|
||||
fromClauseLayout: (value) => isStringChoice(value, FROM_CLAUSE_LAYOUT_VALUES),
|
||||
expressionWidth: (value) => isNumberChoice(value, EXPRESSION_WIDTH_VALUES),
|
||||
linesBetweenQueries: (value) => isNumberChoice(value, LINES_BETWEEN_QUERIES_VALUES),
|
||||
preserveEmptyLines: (value) => typeof value === "boolean",
|
||||
denseOperators: (value) => typeof value === "boolean",
|
||||
newlineBeforeSemicolon: (value) => typeof value === "boolean",
|
||||
paramTypes: isSqlFormatterParamTypes,
|
||||
@@ -191,6 +195,7 @@ export function sqlFormatterOptionSettings(settings: unknown): SqlFormatterOptio
|
||||
fromClauseLayout: normalizeChoice(input.fromClauseLayout, FROM_CLAUSE_LAYOUT_VALUES, DEFAULT_SQL_FORMATTER_SETTINGS.fromClauseLayout),
|
||||
expressionWidth: normalizeNumberChoice(input.expressionWidth, EXPRESSION_WIDTH_VALUES, DEFAULT_SQL_FORMATTER_SETTINGS.expressionWidth),
|
||||
linesBetweenQueries: normalizeNumberChoice(input.linesBetweenQueries, LINES_BETWEEN_QUERIES_VALUES, DEFAULT_SQL_FORMATTER_SETTINGS.linesBetweenQueries),
|
||||
preserveEmptyLines: normalizeBoolean(input.preserveEmptyLines, DEFAULT_SQL_FORMATTER_SETTINGS.preserveEmptyLines),
|
||||
denseOperators: normalizeBoolean(input.denseOperators, DEFAULT_SQL_FORMATTER_SETTINGS.denseOperators),
|
||||
newlineBeforeSemicolon: normalizeBoolean(input.newlineBeforeSemicolon, DEFAULT_SQL_FORMATTER_SETTINGS.newlineBeforeSemicolon),
|
||||
paramTypes: normalizeParamTypes(input.paramTypes, DEFAULT_SQL_FORMATTER_SETTINGS.paramTypes),
|
||||
|
||||
Reference in New Issue
Block a user