Files
t8y2--dbx/packages/app-tests/sqlFormatterConfig.test.ts
2026-07-13 13:09:14 +08:00

277 lines
8.8 KiB
TypeScript
Vendored

import assert from "node:assert/strict";
import { test } from "vitest";
import { DEFAULT_SQL_FORMATTER_SETTINGS, normalizeSqlFormatterSettings, parseSqlFormatterConfig, serializeSqlFormatterConfig, sqlFormatterOptions, syncSqlFormatterConfigDraft } from "../../apps/desktop/src/lib/sql/sqlFormatterConfig.ts";
const defaultOptionSettings = DEFAULT_SQL_FORMATTER_SETTINGS;
test("normalizes empty formatter settings to defaults", () => {
assert.deepEqual(normalizeSqlFormatterSettings({}), DEFAULT_SQL_FORMATTER_SETTINGS);
});
test("keeps valid formatter settings and clamps invalid values", () => {
const settings = normalizeSqlFormatterSettings({
keywordCase: "lower",
dataTypeCase: "upper",
functionCase: "lower",
identifierCase: "upper",
indentStyle: "tabularLeft",
useTabs: true,
tabWidth: 4,
logicalOperatorNewline: "after",
expressionWidth: 120,
linesBetweenQueries: 2,
denseOperators: true,
newlineBeforeSemicolon: true,
paramTypes: { named: [":"], custom: [{ regex: "\\{\\w+\\}" }] },
});
assert.deepEqual(settings, {
...DEFAULT_SQL_FORMATTER_SETTINGS,
keywordCase: "lower",
dataTypeCase: "upper",
functionCase: "lower",
identifierCase: "upper",
indentStyle: "tabularLeft",
useTabs: true,
tabWidth: 4,
logicalOperatorNewline: "after",
expressionWidth: 120,
linesBetweenQueries: 2,
denseOperators: true,
newlineBeforeSemicolon: true,
paramTypes: { named: [":"], custom: [{ regex: "\\{\\w+\\}" }] },
});
assert.deepEqual(
normalizeSqlFormatterSettings({
keywordCase: "camel",
dataTypeCase: "invalid",
functionCase: "invalid",
identifierCase: "invalid",
indentStyle: "wide",
useTabs: "yes",
tabWidth: 99,
logicalOperatorNewline: "middle",
expressionWidth: -1,
linesBetweenQueries: 9,
denseOperators: "true",
newlineBeforeSemicolon: "false",
paramTypes: { named: ["#"] },
editor: { shortcuts: [{ id: "duplicateLine", keys: { windows: "Ctrl+W", linux: "Ctrl+W", macos: "Cmd+W" }, enabled: false }] },
}),
DEFAULT_SQL_FORMATTER_SETTINGS,
);
});
test("serializes formatter config as a stable versioned envelope", () => {
const json = serializeSqlFormatterConfig({
...DEFAULT_SQL_FORMATTER_SETTINGS,
keywordCase: "lower",
});
assert.equal(
json,
JSON.stringify(
{
version: 1,
formatter: "sql-formatter",
options: {
...defaultOptionSettings,
keywordCase: "lower",
},
},
null,
2,
),
);
});
test("parses valid formatter config files", () => {
const result = parseSqlFormatterConfig(
JSON.stringify({
version: 1,
formatter: "sql-formatter",
ignoredTopLevelField: "ok",
options: {
keywordCase: "lower",
functionCase: "upper",
dataTypeCase: "preserve",
identifierCase: "lower",
indentStyle: "tabularRight",
useTabs: false,
tabWidth: 4,
logicalOperatorNewline: "after",
expressionWidth: 80,
linesBetweenQueries: 0,
denseOperators: false,
newlineBeforeSemicolon: true,
paramTypes: { named: [":"], quoted: ["@"], positional: true },
},
editor: {
scope: "legacyJsonEditorScope",
platforms: ["windows", "macos"],
shortcuts: [{ id: "unknownLegacyShortcut", action: "copyLineDown", keys: { windows: "", linux: "Ctrl+W", macos: "Cmd+W" }, enabled: "yes" }],
},
}),
);
assert.equal(result.ok, true);
assert.deepEqual(result.settings, {
...DEFAULT_SQL_FORMATTER_SETTINGS,
keywordCase: "lower",
functionCase: "upper",
dataTypeCase: "preserve",
identifierCase: "lower",
indentStyle: "tabularRight",
useTabs: false,
tabWidth: 4,
logicalOperatorNewline: "after",
expressionWidth: 80,
linesBetweenQueries: 0,
denseOperators: false,
newlineBeforeSemicolon: true,
paramTypes: { named: [":"], quoted: ["@"], positional: true },
});
});
test("ignores legacy editor shortcut fields in formatter config files", () => {
const result = parseSqlFormatterConfig(
JSON.stringify({
version: 1,
formatter: "sql-formatter",
options: {},
editor: {
shortcuts: [{ id: "unknown", keys: { windows: "" }, enabled: "not-a-boolean" }],
},
}),
);
assert.equal(result.ok, true);
if (result.ok) {
assert.deepEqual(result.settings, DEFAULT_SQL_FORMATTER_SETTINGS);
}
});
test("rejects malformed formatter config files", () => {
assert.deepEqual(parseSqlFormatterConfig("{bad json").ok, false);
assert.deepEqual(parseSqlFormatterConfig(JSON.stringify({ version: 2, formatter: "sql-formatter", options: {} })).ok, false);
assert.deepEqual(parseSqlFormatterConfig(JSON.stringify({ version: 1, formatter: "prettier", options: {} })).ok, false);
assert.deepEqual(parseSqlFormatterConfig(JSON.stringify({ version: 1, formatter: "sql-formatter", options: { unknown: true } })).ok, false);
});
test("rejects invalid known formatter option values when parsing config files", () => {
const invalidKeywordCase = parseSqlFormatterConfig(JSON.stringify({ version: 1, formatter: "sql-formatter", options: { keywordCase: "camel" } }));
assert.equal(invalidKeywordCase.ok, false);
if (!invalidKeywordCase.ok) assert.match(invalidKeywordCase.message, /keywordCase/);
const invalidBoolean = parseSqlFormatterConfig(JSON.stringify({ version: 1, formatter: "sql-formatter", options: { useTabs: "yes" } }));
assert.equal(invalidBoolean.ok, false);
if (!invalidBoolean.ok) assert.match(invalidBoolean.message, /useTabs/);
const invalidNumericChoice = parseSqlFormatterConfig(JSON.stringify({ version: 1, formatter: "sql-formatter", options: { tabWidth: 3 } }));
assert.equal(invalidNumericChoice.ok, false);
if (!invalidNumericChoice.ok) assert.match(invalidNumericChoice.message, /tabWidth/);
const invalidParams = parseSqlFormatterConfig(JSON.stringify({ version: 1, formatter: "sql-formatter", options: { params: ["42"] } }));
assert.equal(invalidParams.ok, false);
if (!invalidParams.ok) assert.match(invalidParams.message, /params/);
const legacyNullParams = parseSqlFormatterConfig(JSON.stringify({ version: 1, formatter: "sql-formatter", options: { params: null } }));
assert.equal(legacyNullParams.ok, true);
const invalidParamTypes = parseSqlFormatterConfig(JSON.stringify({ version: 1, formatter: "sql-formatter", options: { paramTypes: { custom: [{ regex: "" }] } } }));
assert.equal(invalidParamTypes.ok, false);
if (!invalidParamTypes.ok) assert.match(invalidParamTypes.message, /paramTypes/);
});
test("syncs valid JSON drafts so outer settings apply can persist them", () => {
let synced = DEFAULT_SQL_FORMATTER_SETTINGS;
const result = syncSqlFormatterConfigDraft(
JSON.stringify({
version: 1,
formatter: "sql-formatter",
options: {
...defaultOptionSettings,
keywordCase: "lower",
tabWidth: 4,
},
}),
(settings) => {
synced = settings;
},
);
assert.equal(result.ok, true);
assert.deepEqual(synced, {
...DEFAULT_SQL_FORMATTER_SETTINGS,
keywordCase: "lower",
tabWidth: 4,
});
});
test("does not sync invalid JSON drafts", () => {
let synced = DEFAULT_SQL_FORMATTER_SETTINGS;
const result = syncSqlFormatterConfigDraft(
JSON.stringify({
version: 1,
formatter: "sql-formatter",
options: {
...defaultOptionSettings,
keywordCase: "camel",
},
}),
(settings) => {
synced = settings;
},
);
assert.equal(result.ok, false);
assert.deepEqual(synced, DEFAULT_SQL_FORMATTER_SETTINGS);
});
test("maps DBX formatter settings to sql-formatter options", () => {
assert.deepEqual(
sqlFormatterOptions({
...DEFAULT_SQL_FORMATTER_SETTINGS,
keywordCase: "lower",
useTabs: true,
newlineBeforeSemicolon: true,
}),
{
keywordCase: "lower",
dataTypeCase: "preserve",
functionCase: "preserve",
identifierCase: "preserve",
indentStyle: "standard",
useTabs: true,
tabWidth: 2,
logicalOperatorNewline: "before",
expressionWidth: 50,
linesBetweenQueries: 1,
denseOperators: false,
newlineBeforeSemicolon: true,
},
);
assert.deepEqual(
sqlFormatterOptions({
...DEFAULT_SQL_FORMATTER_SETTINGS,
paramTypes: { positional: true },
}),
{
keywordCase: "upper",
dataTypeCase: "preserve",
functionCase: "preserve",
identifierCase: "preserve",
indentStyle: "standard",
useTabs: false,
tabWidth: 2,
logicalOperatorNewline: "before",
expressionWidth: 50,
linesBetweenQueries: 1,
denseOperators: false,
newlineBeforeSemicolon: false,
paramTypes: { positional: true },
},
);
});