inline-sql-toolkit 0.5.1 → 0.5.3
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 +13 -0
- package/README.md +37 -1
- package/dist/cli.js +71 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.3 - 2026-10-10
|
|
4
|
+
|
|
5
|
+
- Feature: a "# inline-sql: skip" comment excludes a specific SQL literal from formatting (as a trailing comment on the closing quote line or on a dedicated line directly preceding the literal).
|
|
6
|
+
|
|
7
|
+
## 0.5.2 - 2026-10-09
|
|
8
|
+
|
|
9
|
+
- Fixed: with `inlineSql.format.commaPosition: "before"`, the rest of a
|
|
10
|
+
multi-line item (`CASE … END`, a subquery, a wrapped function call) now
|
|
11
|
+
moves right with its leading `, `, so `END` and the closing `)` no longer
|
|
12
|
+
line up with the comma. Only lines up to the `)` / `]` / `END` that closes
|
|
13
|
+
the item move; a following `JOIN` or statement stays put. Nested items add
|
|
14
|
+
up; lines that continue a string or block comment are left untouched.
|
|
15
|
+
|
|
3
16
|
## 0.5.1 - 2026-10-02
|
|
4
17
|
|
|
5
18
|
- Security: pins patched versions of OSV-flagged transitive dependencies
|
package/README.md
CHANGED
|
@@ -246,6 +246,41 @@ order, or the candidate is skipped (`FORMATTER_FAILED`).
|
|
|
246
246
|
A single-quoted literal stays on one line and keeps its leading and trailing
|
|
247
247
|
spaces, because the string may be joined to other text at runtime.
|
|
248
248
|
|
|
249
|
+
### Skipping a literal
|
|
250
|
+
|
|
251
|
+
To exclude a specific SQL literal from formatting, add an `# inline-sql: skip` pragma comment (case-insensitive, matched with `/\binline-sql:\s*skip(?![\w-])/i`). Other comments such as `# noqa: E501` or `# type: ignore` may share the same comment line.
|
|
252
|
+
|
|
253
|
+
You can place the pragma in either of two ways:
|
|
254
|
+
|
|
255
|
+
1. **Trailing comment on the closing line**: on the line where the literal ends (the closing quote line).
|
|
256
|
+
```python
|
|
257
|
+
q = "select a,b from t" # inline-sql: skip
|
|
258
|
+
q = """--sql
|
|
259
|
+
select a,
|
|
260
|
+
b
|
|
261
|
+
from t
|
|
262
|
+
""" # inline-sql: skip
|
|
263
|
+
```
|
|
264
|
+
2. **Dedicated comment line immediately preceding the literal**: on the line directly above where the literal starts, containing only whitespace followed by the `# inline-sql: skip` comment.
|
|
265
|
+
```python
|
|
266
|
+
# inline-sql: skip
|
|
267
|
+
q = """--sql
|
|
268
|
+
...
|
|
269
|
+
"""
|
|
270
|
+
query = (
|
|
271
|
+
# inline-sql: skip
|
|
272
|
+
"""--sql ..."""
|
|
273
|
+
)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Notes on skipping behavior:
|
|
277
|
+
|
|
278
|
+
- On triple-quoted strings, any text after the opening quotes (such as `"""--sql # inline-sql: skip`) is part of the string body, not a Python comment, so a pragma placed there has no effect.
|
|
279
|
+
- A trailing comment on a preceding statement (e.g. `a = "select 1" # inline-sql: skip`) does not affect a literal starting on the next line (`b = "select 2"`). Dedicated comment lines must consist only of whitespace and the comment.
|
|
280
|
+
- Syntax highlighting is powered by TextMate grammar and is not affected by `# inline-sql: skip`. Only formatting excludes the literal.
|
|
281
|
+
- When running **Format at Cursor** on a skipped literal, the command reports `NO_SQL_CANDIDATE`.
|
|
282
|
+
- Both CLI `--check` and `--write` honor `# inline-sql: skip` with the exact same rules: skipped literals are never formatted, never reported on stderr as skipped candidates, and do not cause `--check` to fail.
|
|
283
|
+
|
|
249
284
|
## Trust, privacy, and offline behavior
|
|
250
285
|
|
|
251
286
|
In an untrusted workspace the extension provides highlighting only. The three
|
|
@@ -268,7 +303,8 @@ over the network, passed to a shell/database, or executed. The bundled
|
|
|
268
303
|
`INVALID_CONFIGURATION`, or `PROCESS_FAILED`).
|
|
269
304
|
- **SQL looks different than expected:** formatting does not validate SQL or
|
|
270
305
|
infer a dialect. Adjust the settings above and review the source-level
|
|
271
|
-
candidate before applying the one-step edit
|
|
306
|
+
candidate before applying the one-step edit, or exclude the literal with
|
|
307
|
+
`# inline-sql: skip`.
|
|
272
308
|
|
|
273
309
|
For security reporting, see [SECURITY.md](SECURITY.md). For source-free bug
|
|
274
310
|
reports and diagnostic reason codes, see [SUPPORT.md](SUPPORT.md). Licensing and
|
package/dist/cli.js
CHANGED
|
@@ -808,6 +808,7 @@ function stringSurfaceAt(source, index) {
|
|
|
808
808
|
}
|
|
809
809
|
function scanSource(source) {
|
|
810
810
|
const surfaces = [];
|
|
811
|
+
const comments = [];
|
|
811
812
|
let unterminated = false;
|
|
812
813
|
let index = 0;
|
|
813
814
|
while (index < source.length) {
|
|
@@ -818,6 +819,7 @@ function scanSource(source) {
|
|
|
818
819
|
}
|
|
819
820
|
if (char === "#") {
|
|
820
821
|
const end = source.indexOf("\n", index);
|
|
822
|
+
comments.push(new SourceSpan(index, end === -1 ? source.length : end));
|
|
821
823
|
index = end === -1 ? source.length : end;
|
|
822
824
|
continue;
|
|
823
825
|
}
|
|
@@ -837,7 +839,7 @@ function scanSource(source) {
|
|
|
837
839
|
}
|
|
838
840
|
index++;
|
|
839
841
|
}
|
|
840
|
-
return { surfaces, unterminated };
|
|
842
|
+
return { surfaces, comments, unterminated };
|
|
841
843
|
}
|
|
842
844
|
function scanFstringFields(source, contentSpan) {
|
|
843
845
|
const fields = [];
|
|
@@ -919,6 +921,7 @@ function fstringKind(prefix) {
|
|
|
919
921
|
}
|
|
920
922
|
|
|
921
923
|
// src/python-analysis/literals.ts
|
|
924
|
+
var SKIP_PRAGMA = /\binline-sql:\s*skip(?![\w-])/i;
|
|
922
925
|
function onlyWhitespace(text) {
|
|
923
926
|
return /^[\s]*$/.test(text);
|
|
924
927
|
}
|
|
@@ -941,7 +944,25 @@ function isConcatenated(source, surfaces, index) {
|
|
|
941
944
|
}
|
|
942
945
|
function analyzeDocument(source) {
|
|
943
946
|
const sourceMap = SourceMap.fromText(source);
|
|
944
|
-
const { surfaces, unterminated } = scanSource(source);
|
|
947
|
+
const { surfaces, comments, unterminated } = scanSource(source);
|
|
948
|
+
const trailingPragmas = /* @__PURE__ */ new Set();
|
|
949
|
+
const ownLinePragmas = /* @__PURE__ */ new Set();
|
|
950
|
+
for (const span of comments) {
|
|
951
|
+
const commentText2 = source.slice(span.start, span.end);
|
|
952
|
+
if (!SKIP_PRAGMA.test(commentText2)) continue;
|
|
953
|
+
const line = sourceMap.vscodeFromOffset(span.start).line;
|
|
954
|
+
const lineStartOffset = sourceMap.offsetFromVscode(line, 0);
|
|
955
|
+
const prefix = source.slice(lineStartOffset, span.start);
|
|
956
|
+
if (/^[ \t]*$/.test(prefix)) {
|
|
957
|
+
ownLinePragmas.add(line);
|
|
958
|
+
} else {
|
|
959
|
+
trailingPragmas.add(line);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
const skipPragmaLines = {
|
|
963
|
+
trailing: trailingPragmas,
|
|
964
|
+
ownLine: ownLinePragmas
|
|
965
|
+
};
|
|
945
966
|
const supported = [];
|
|
946
967
|
const unsupported = [];
|
|
947
968
|
surfaces.forEach((surface, index) => {
|
|
@@ -1005,7 +1026,8 @@ function analyzeDocument(source) {
|
|
|
1005
1026
|
sourceMap,
|
|
1006
1027
|
unterminated,
|
|
1007
1028
|
supported: [...supported].sort((left, right) => left.span.start - right.span.start),
|
|
1008
|
-
unsupported: [...unsupported].sort((left, right) => left.span.start - right.span.start)
|
|
1029
|
+
unsupported: [...unsupported].sort((left, right) => left.span.start - right.span.start),
|
|
1030
|
+
skipPragmaLines
|
|
1009
1031
|
};
|
|
1010
1032
|
}
|
|
1011
1033
|
|
|
@@ -1907,8 +1929,9 @@ function wrappingComma(line) {
|
|
|
1907
1929
|
if (comma < 0) return -1;
|
|
1908
1930
|
return /^[ \t]*(?:--.*)?$/.test(line.slice(comma + 1)) ? comma : -1;
|
|
1909
1931
|
}
|
|
1910
|
-
function moveCommasToLineStarts(text) {
|
|
1932
|
+
function moveCommasToLineStarts(text, dialect) {
|
|
1911
1933
|
const lines = text.split("\n");
|
|
1934
|
+
const inserts = /* @__PURE__ */ new Map();
|
|
1912
1935
|
for (let index = 0; index + 1 < lines.length; index++) {
|
|
1913
1936
|
const line = lines[index] ?? "";
|
|
1914
1937
|
const next = lines[index + 1] ?? "";
|
|
@@ -1920,8 +1943,43 @@ function moveCommasToLineStarts(text) {
|
|
|
1920
1943
|
const content = nextParts?.[2] ?? "";
|
|
1921
1944
|
lines[index] = `${line.slice(0, comma)}${line.slice(comma + 1)}`.trimEnd();
|
|
1922
1945
|
lines[index + 1] = `${indent}, ${content}`;
|
|
1946
|
+
inserts.set(index + 1, indent.length);
|
|
1947
|
+
}
|
|
1948
|
+
if (inserts.size === 0) return text;
|
|
1949
|
+
return shiftMovedItems(lines, inserts, dialect).join("\n");
|
|
1950
|
+
}
|
|
1951
|
+
function shiftMovedItems(lines, inserts, dialect) {
|
|
1952
|
+
const starts = [];
|
|
1953
|
+
let offset = 0;
|
|
1954
|
+
for (const line of lines) {
|
|
1955
|
+
starts.push(offset);
|
|
1956
|
+
offset += line.length + 1;
|
|
1957
|
+
}
|
|
1958
|
+
const tokens = lexSql(lines.join("\n"), dialect);
|
|
1959
|
+
const textLines = /* @__PURE__ */ new Set();
|
|
1960
|
+
for (const token of tokens) {
|
|
1961
|
+
if (token.kind === "space" || !token.text.includes("\n")) continue;
|
|
1962
|
+
starts.forEach((start, line) => {
|
|
1963
|
+
if (start > token.start && start < token.end) textLines.add(line);
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1966
|
+
const shifts = new Array(lines.length).fill(0);
|
|
1967
|
+
for (const [target, column] of inserts) {
|
|
1968
|
+
for (let index = target + 1; index < lines.length; index++) {
|
|
1969
|
+
const line = lines[index] ?? "";
|
|
1970
|
+
const indent = line.length - line.trimStart().length;
|
|
1971
|
+
if (indent === line.length || textLines.has(index)) continue;
|
|
1972
|
+
if (indent < column) break;
|
|
1973
|
+
if (indent === column && !/^(?:[)\]]|END\b)/i.test(line.slice(indent))) break;
|
|
1974
|
+
shifts[index] = (shifts[index] ?? 0) + 2;
|
|
1975
|
+
}
|
|
1923
1976
|
}
|
|
1924
|
-
return lines.
|
|
1977
|
+
return lines.map((line, index) => {
|
|
1978
|
+
const shift = shifts[index] ?? 0;
|
|
1979
|
+
if (shift === 0) return line;
|
|
1980
|
+
const indent = line.length - line.trimStart().length;
|
|
1981
|
+
return `${line.slice(0, indent)}${" ".repeat(shift)}${line.slice(indent)}`;
|
|
1982
|
+
});
|
|
1925
1983
|
}
|
|
1926
1984
|
var DOLLAR_QUOTE = /\$[A-Za-z_][A-Za-z0-9_]*\$|\$\$/y;
|
|
1927
1985
|
function rejoinFunctionCalls(text) {
|
|
@@ -2047,7 +2105,7 @@ function formatOnce(analysis, literal, detection, options, nonce, sqlFormatter,
|
|
|
2047
2105
|
formatted = rejoinFunctionCalls(formatted);
|
|
2048
2106
|
}
|
|
2049
2107
|
if (options.commaPosition === "before") {
|
|
2050
|
-
formatted = moveCommasToLineStarts(formatted);
|
|
2108
|
+
formatted = moveCommasToLineStarts(formatted, options.dialect);
|
|
2051
2109
|
}
|
|
2052
2110
|
formatted = breakTrailingDistributeLines(formatted, options.dialect);
|
|
2053
2111
|
const difference = sqlTokenDifference(plan.protectedSql, formatted, options.dialect);
|
|
@@ -2175,6 +2233,12 @@ var MAX_CANDIDATE_BYTES = 1024 * 1024;
|
|
|
2175
2233
|
var MAX_CANDIDATES = 1e3;
|
|
2176
2234
|
var ResourceLimitError = class extends Error {
|
|
2177
2235
|
};
|
|
2236
|
+
function isSkippedByPragma(literal, analysis) {
|
|
2237
|
+
const startLine = analysis.sourceMap.vscodeFromOffset(literal.span.start).line;
|
|
2238
|
+
const endLine = analysis.sourceMap.vscodeFromOffset(literal.span.end).line;
|
|
2239
|
+
const { trailing, ownLine } = analysis.skipPragmaLines;
|
|
2240
|
+
return ownLine.has(startLine - 1) || trailing.has(endLine) || ownLine.has(endLine);
|
|
2241
|
+
}
|
|
2178
2242
|
function discover(analysis) {
|
|
2179
2243
|
const literals = [
|
|
2180
2244
|
...analysis.supported,
|
|
@@ -2183,7 +2247,7 @@ function discover(analysis) {
|
|
|
2183
2247
|
const units = literals.map((literal) => ({
|
|
2184
2248
|
literal,
|
|
2185
2249
|
detection: detectSql(literal, analysis.sourceMap)
|
|
2186
|
-
})).filter((unit) => unit.detection.matched);
|
|
2250
|
+
})).filter((unit) => unit.detection.matched && !isSkippedByPragma(unit.literal, analysis));
|
|
2187
2251
|
return [...units].sort((left, right) => left.literal.span.start - right.literal.span.start);
|
|
2188
2252
|
}
|
|
2189
2253
|
function selectUnits(units, target, sourceMap) {
|