inline-sql-toolkit 0.4.10 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.12 - 2026-09-24
4
+
5
+ - Feature: added the `inlineSql.format.keepFunctionsInline` setting (default
6
+ `false`). `sql-formatter` has no option that holds function arguments on
7
+ one line — it breaks `CASE` structurally regardless of `wrapAfter` — so the
8
+ extension re-joins the line breaks the engine inserts inside `word(...)`
9
+ groups as a post-pass over its output. With the setting on,
10
+ `COUNT(CASE WHEN a THEN 1 ELSE 0 END)` stays on a single line while select
11
+ lists, clause breaks, and `AND` / `OR` chains keep their usual layout.
12
+ - The same choice is exposed everywhere the other options are: the VS Code
13
+ setting, the CLI flag `--keep-functions-inline`, and
14
+ `"keepFunctionsInline"` in `.inline-sql.json`, under the unchanged CLI
15
+ flags > configuration file > defaults precedence.
16
+ - Safety: only newlines in code state are removed. A newline inside a string
17
+ literal, a `$$ … $$` body, or a block comment is copied verbatim, and the
18
+ newline that terminates a `-- line comment` is kept, so literal content can
19
+ never change and no code can fall into a comment. The default `false`
20
+ reproduces the previous output byte for byte, and the fixed-point loop still
21
+ skips any candidate whose formatting does not converge.
22
+
23
+ ## 0.4.11 - 2026-09-24
24
+
25
+ - Feature: added the `inlineSql.format.commaPosition` setting (`after` |
26
+ `before`, default `after`) for codebases that want a wrapped item's comma at
27
+ the start of the next line instead of the end of the previous one. The
28
+ default reproduces the previous output byte for byte, so existing files do
29
+ not move until the setting is turned on; `before` emits the comma at the
30
+ next line's indent in front of the item, and a trailing `-- comment` stays
31
+ with its own column (`order_id -- note` followed by `, order_date -- note`)
32
+ rather than pinning the comma behind it.
33
+ - The same choice is exposed everywhere the other options are: the VS Code
34
+ setting, the CLI flag `--comma-position after|before`, and
35
+ `"commaPosition"` in `.inline-sql.json`, under the unchanged CLI flags >
36
+ configuration file > defaults precedence.
37
+ - Safety: `sql-formatter` removed its own `commaPosition` option long ago, so
38
+ the move is a small post-pass over its output. A scanner locates the
39
+ wrapping separator comma and never moves one from inside a quoted string
40
+ (`'...'`, `"..."`, backticks) or from after a `--` line comment, and a
41
+ candidate whose output still fails to converge to a fixed point is skipped
42
+ untouched as before, so no file can be rewritten with corrupted SQL.
43
+
3
44
  ## 0.4.10 - 2026-09-19
4
45
 
5
46
  - CI: the npm publish job is now OIDC-only. The dormant `NPM_TOKEN` path that was
package/README.md CHANGED
@@ -110,6 +110,13 @@ later atomic precondition.
110
110
  aliases (default `true`).
111
111
  - `inlineSql.format.dialect`: SQL dialect used by the formatter (`sql`,
112
112
  `mysql`, `postgresql`, or `sqlite`; default `postgresql`).
113
+ - `inlineSql.format.commaPosition`: `after` (default) keeps a wrapping comma at
114
+ the end of the previous line; `before` moves it to the start of the next
115
+ line.
116
+ - `inlineSql.format.keepFunctionsInline`: re-join the formatter's line breaks
117
+ inside `word(...)` groups so `SUM(...)`, `COUNT(CASE ... END)`, and nested
118
+ calls stay on one line (default `false`). Newlines inside string literals and
119
+ comments are never removed.
113
120
 
114
121
  The extension highlights inline SQL with an injected TextMate grammar: SQL
115
122
  strings that start with `-- sql` (or a leading SQL keyword) are embedded as
@@ -144,6 +151,8 @@ When run without file arguments, the CLI reads Python source from standard input
144
151
  | `--wrap-after <20-500>` | Preferred expression line width | `88` |
145
152
  | `--no-space-around-operators` | Keep dense operators | spaced |
146
153
  | `--no-ordinals` | Do not replace `GROUP BY` / `ORDER BY` ordinals with column names | replace |
154
+ | `--comma-position <pos>` | Where a wrapping comma sits: `after` or `before` | `after` |
155
+ | `--keep-functions-inline` | Keep `SUM(...)` / `COUNT(CASE ... END)` on one line | off |
147
156
  | `-c, --config <file>` | Configuration JSON file | Nearest `.inline-sql.json` |
148
157
  | `-h, --help` | Show usage help | |
149
158
  | `--version` | Show version number | |
@@ -162,7 +171,9 @@ The CLI automatically searches for a `.inline-sql.json` file in the current work
162
171
  "wrapAfter": 88,
163
172
  "useSpaceAroundOperators": true,
164
173
  "replaceOrdinals": true,
165
- "dialect": "postgresql"
174
+ "dialect": "postgresql",
175
+ "commaPosition": "after",
176
+ "keepFunctionsInline": false
166
177
  }
167
178
  }
168
179
  ```
package/dist/cli.js CHANGED
@@ -494,7 +494,9 @@ function resolveFormatOptions(raw) {
494
494
  const useSpaceAroundOperators = raw.useSpaceAroundOperators === void 0 ? true : raw.useSpaceAroundOperators;
495
495
  const replaceOrdinals2 = raw.replaceOrdinals === void 0 ? true : raw.replaceOrdinals;
496
496
  const dialect = raw.dialect === void 0 ? "postgresql" : raw.dialect;
497
- if (keywordCase !== "upper" && keywordCase !== "lower" && keywordCase !== "preserve" || !integerBetween(indentWidth, 1, 8) || !integerBetween(wrapAfter, 20, 500) || typeof useSpaceAroundOperators !== "boolean" || typeof replaceOrdinals2 !== "boolean" || dialect !== "sql" && dialect !== "mysql" && dialect !== "postgresql" && dialect !== "sqlite") {
497
+ const commaPosition = raw.commaPosition === void 0 ? "after" : raw.commaPosition;
498
+ const keepFunctionsInline = raw.keepFunctionsInline === void 0 ? false : raw.keepFunctionsInline;
499
+ if (keywordCase !== "upper" && keywordCase !== "lower" && keywordCase !== "preserve" || !integerBetween(indentWidth, 1, 8) || !integerBetween(wrapAfter, 20, 500) || typeof useSpaceAroundOperators !== "boolean" || typeof replaceOrdinals2 !== "boolean" || dialect !== "sql" && dialect !== "mysql" && dialect !== "postgresql" && dialect !== "sqlite" || commaPosition !== "after" && commaPosition !== "before" || typeof keepFunctionsInline !== "boolean") {
498
500
  return { ok: false, reason: "INVALID_CONFIGURATION" };
499
501
  }
500
502
  return {
@@ -505,7 +507,9 @@ function resolveFormatOptions(raw) {
505
507
  wrapAfter,
506
508
  useSpaceAroundOperators,
507
509
  replaceOrdinals: replaceOrdinals2,
508
- dialect
510
+ dialect,
511
+ commaPosition,
512
+ keepFunctionsInline
509
513
  }
510
514
  };
511
515
  }
@@ -1584,6 +1588,144 @@ function breakTrailingDistributeLines(text) {
1584
1588
  ${indent}${rest}`
1585
1589
  );
1586
1590
  }
1591
+ function wrappingComma(line) {
1592
+ let comma = -1;
1593
+ for (let index = 0; index < line.length; index++) {
1594
+ const char = line[index];
1595
+ if (char === "'" || char === '"' || char === "`") {
1596
+ for (index += 1; index < line.length && line[index] !== char; index++) {
1597
+ if (line[index] === "\\") index += 1;
1598
+ }
1599
+ continue;
1600
+ }
1601
+ if (char === "-" && line[index + 1] === "-") break;
1602
+ if (char === ",") comma = index;
1603
+ }
1604
+ if (comma < 0) return -1;
1605
+ return /^[ \t]*(?:--.*)?$/.test(line.slice(comma + 1)) ? comma : -1;
1606
+ }
1607
+ function moveCommasToLineStarts(text) {
1608
+ const lines = text.split("\n");
1609
+ for (let index = 0; index + 1 < lines.length; index++) {
1610
+ const line = lines[index] ?? "";
1611
+ const next = lines[index + 1] ?? "";
1612
+ if (next.trim() === "") continue;
1613
+ const comma = wrappingComma(line);
1614
+ if (comma < 0 || line.slice(0, comma).trim() === "") continue;
1615
+ const nextParts = /^([ \t]*)([\s\S]*)$/.exec(next);
1616
+ const indent = nextParts?.[1] ?? "";
1617
+ const content = nextParts?.[2] ?? "";
1618
+ lines[index] = `${line.slice(0, comma)}${line.slice(comma + 1)}`.trimEnd();
1619
+ lines[index + 1] = `${indent}, ${content}`;
1620
+ }
1621
+ return lines.join("\n");
1622
+ }
1623
+ var DOLLAR_QUOTE = /\$[A-Za-z_][A-Za-z0-9_]*\$|\$\$/y;
1624
+ function rejoinFunctionCalls(text) {
1625
+ const stack = [];
1626
+ let out = "";
1627
+ let i = 0;
1628
+ const at = (index) => text.charAt(index);
1629
+ const isCallOpener = () => {
1630
+ const match = /[A-Za-z_][A-Za-z0-9_]*\s*$/.exec(out);
1631
+ if (match === null) return false;
1632
+ const before = out.slice(0, match.index);
1633
+ return before === "" || !/[A-Za-z0-9_]$/.test(before);
1634
+ };
1635
+ while (i < text.length) {
1636
+ const ch = at(i);
1637
+ if (ch === "'" || ch === '"' || ch === "`") {
1638
+ const quote = ch;
1639
+ out += ch;
1640
+ i += 1;
1641
+ while (i < text.length) {
1642
+ if (at(i) === quote && at(i + 1) === quote) {
1643
+ out += at(i) + at(i + 1);
1644
+ i += 2;
1645
+ continue;
1646
+ }
1647
+ out += at(i);
1648
+ i += 1;
1649
+ if (at(i - 1) === quote) break;
1650
+ if (at(i - 1) === "\\" && quote !== "`" && i < text.length) {
1651
+ out += at(i);
1652
+ i += 1;
1653
+ }
1654
+ }
1655
+ continue;
1656
+ }
1657
+ if (ch === "$") {
1658
+ DOLLAR_QUOTE.lastIndex = i;
1659
+ const dollar = DOLLAR_QUOTE.exec(text);
1660
+ if (dollar !== null) {
1661
+ const end = text.indexOf(dollar[0], i + dollar[0].length);
1662
+ const stop = end === -1 ? text.length : end + dollar[0].length;
1663
+ out += text.slice(i, stop);
1664
+ i = stop;
1665
+ continue;
1666
+ }
1667
+ }
1668
+ if (ch === "-" && at(i + 1) === "-" || ch === "#") {
1669
+ while (i < text.length && at(i) !== "\n") {
1670
+ out += at(i);
1671
+ i += 1;
1672
+ }
1673
+ if (i < text.length) {
1674
+ out += at(i);
1675
+ i += 1;
1676
+ }
1677
+ continue;
1678
+ }
1679
+ if (ch === "/" && at(i + 1) === "*") {
1680
+ out += "/*";
1681
+ i += 2;
1682
+ while (i < text.length && !(at(i) === "*" && at(i + 1) === "/")) {
1683
+ out += at(i);
1684
+ i += 1;
1685
+ }
1686
+ if (i < text.length) {
1687
+ out += "*/";
1688
+ i += 2;
1689
+ }
1690
+ continue;
1691
+ }
1692
+ if (ch === "\n") {
1693
+ if (stack.includes(true)) {
1694
+ let indent = i + 1;
1695
+ while (indent < text.length && (at(indent) === " " || at(indent) === " ")) {
1696
+ indent += 1;
1697
+ }
1698
+ let peek = indent;
1699
+ while (peek < text.length && (at(peek) === "\n" || at(peek) === " " || at(peek) === " ")) {
1700
+ peek += 1;
1701
+ }
1702
+ const next = at(peek);
1703
+ const prev = out.slice(-1);
1704
+ i = indent;
1705
+ if (prev !== "(" && next !== "," && next !== ")") out += " ";
1706
+ } else {
1707
+ out += ch;
1708
+ i += 1;
1709
+ }
1710
+ continue;
1711
+ }
1712
+ if (ch === "(") {
1713
+ stack.push(isCallOpener());
1714
+ out += ch;
1715
+ i += 1;
1716
+ continue;
1717
+ }
1718
+ if (ch === ")") {
1719
+ stack.pop();
1720
+ out += ch;
1721
+ i += 1;
1722
+ continue;
1723
+ }
1724
+ out += ch;
1725
+ i += 1;
1726
+ }
1727
+ return out;
1728
+ }
1587
1729
  function formatOnce(analysis, literal, detection, options, nonce, sqlFormatter) {
1588
1730
  const plan = buildProtectionPlan(analysis.sourceMap, literal, detection, nonce);
1589
1731
  let formatted = sqlFormatter(plan.protectedSql, {
@@ -1598,6 +1740,12 @@ function formatOnce(analysis, literal, detection, options, nonce, sqlFormatter)
1598
1740
  }
1599
1741
  formatted = breakTrailingFieldMarkers(formatted);
1600
1742
  formatted = moveCommasBeforeLineComments(formatted);
1743
+ if (options.keepFunctionsInline) {
1744
+ formatted = rejoinFunctionCalls(formatted);
1745
+ }
1746
+ if (options.commaPosition === "before") {
1747
+ formatted = moveCommasToLineStarts(formatted);
1748
+ }
1601
1749
  formatted = breakTrailingDistributeLines(formatted);
1602
1750
  const restored = restoreProtected(formatted, plan);
1603
1751
  const resolved = options.replaceOrdinals ? replaceOrdinals(restored) : restored;
@@ -1824,7 +1972,7 @@ function formatDocument(source, options, target, nonce, sqlFormatter, logger) {
1824
1972
  };
1825
1973
  if (logger !== void 0) {
1826
1974
  logger(
1827
- `format: dialect=${options.dialect} keywordCase=${options.keywordCase} indentWidth=${options.indentWidth} wrapAfter=${options.wrapAfter} useSpaceAroundOperators=${options.useSpaceAroundOperators} replaceOrdinals=${options.replaceOrdinals} discovered=${summary.discovered} selected=${summary.selected} changed=${summary.changed} unchanged=${summary.unchanged} skipped=${summary.skipped}${skipReasons.length > 0 ? ` reasons=[${skipReasons.join(", ")}]` : ""}`
1975
+ `format: dialect=${options.dialect} keywordCase=${options.keywordCase} indentWidth=${options.indentWidth} wrapAfter=${options.wrapAfter} useSpaceAroundOperators=${options.useSpaceAroundOperators} replaceOrdinals=${options.replaceOrdinals} commaPosition=${options.commaPosition} keepFunctionsInline=${options.keepFunctionsInline} discovered=${summary.discovered} selected=${summary.selected} changed=${summary.changed} unchanged=${summary.unchanged} skipped=${summary.skipped}${skipReasons.length > 0 ? ` reasons=[${skipReasons.join(", ")}]` : ""}`
1828
1976
  );
1829
1977
  }
1830
1978
  return {
@@ -22476,6 +22624,8 @@ var USAGE = `Usage: inline-sql-toolkit [options] [files...]
22476
22624
  --wrap-after <20-500> (default: 88)
22477
22625
  --no-space-around-operators keep dense operators (default: spaced)
22478
22626
  --no-ordinals do not replace GROUP BY / ORDER BY ordinals
22627
+ --comma-position <pos> after | before (default: after)
22628
+ --keep-functions-inline keep SUM(...) / COUNT(CASE ...) on one line
22479
22629
  -c, --config <file> config JSON (default: nearest .inline-sql.json)
22480
22630
  -h, --help / --version`;
22481
22631
  function printError(message) {
@@ -22534,7 +22684,9 @@ function buildRawOptions(fileOptions, cliValues) {
22534
22684
  indentWidth: cliValues["indent-width"] !== void 0 ? Number(cliValues["indent-width"]) : fileOptions.indentWidth,
22535
22685
  wrapAfter: cliValues["wrap-after"] !== void 0 ? Number(cliValues["wrap-after"]) : fileOptions.wrapAfter,
22536
22686
  useSpaceAroundOperators: cliValues["no-space-around-operators"] ? false : fileOptions.useSpaceAroundOperators,
22537
- replaceOrdinals: cliValues["no-ordinals"] ? false : fileOptions.replaceOrdinals
22687
+ replaceOrdinals: cliValues["no-ordinals"] ? false : fileOptions.replaceOrdinals,
22688
+ commaPosition: cliValues["comma-position"] ?? fileOptions.commaPosition,
22689
+ keepFunctionsInline: cliValues["keep-functions-inline"] ? true : fileOptions.keepFunctionsInline
22538
22690
  };
22539
22691
  }
22540
22692
  function formatPythonSource(text, options, logger) {
@@ -22570,6 +22722,8 @@ function runCli(argv) {
22570
22722
  "wrap-after": { type: "string" },
22571
22723
  "no-space-around-operators": { type: "boolean", default: false },
22572
22724
  "no-ordinals": { type: "boolean", default: false },
22725
+ "comma-position": { type: "string" },
22726
+ "keep-functions-inline": { type: "boolean", default: false },
22573
22727
  config: { type: "string", short: "c" },
22574
22728
  help: { type: "boolean", short: "h", default: false },
22575
22729
  version: { type: "boolean", default: false }
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "bugs": {
12
12
  "url": "https://github.com/hidenobunagai/inline-sql-toolkit/issues"
13
13
  },
14
- "version": "0.4.10",
14
+ "version": "0.4.12",
15
15
  "icon": "icon.png",
16
16
  "type": "module",
17
17
  "bin": {
@@ -104,6 +104,22 @@
104
104
  "default": "postgresql",
105
105
  "scope": "resource",
106
106
  "description": "%configuration.format.dialect.description%"
107
+ },
108
+ "inlineSql.format.commaPosition": {
109
+ "type": "string",
110
+ "enum": [
111
+ "after",
112
+ "before"
113
+ ],
114
+ "default": "after",
115
+ "scope": "resource",
116
+ "description": "%configuration.format.commaPosition.description%"
117
+ },
118
+ "inlineSql.format.keepFunctionsInline": {
119
+ "type": "boolean",
120
+ "default": false,
121
+ "scope": "resource",
122
+ "description": "%configuration.format.keepFunctionsInline.description%"
107
123
  }
108
124
  }
109
125
  },