inline-sql-toolkit 0.5.3 → 0.6.0
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/.formatignore +2 -0
- package/.oxfmtrc.json +40 -0
- package/CHANGELOG.md +10 -0
- package/README.md +3 -2
- package/dist/cli.js +105 -4
- package/package.json +9 -7
- package/scripts/format-check.sh +58 -0
package/.formatignore
ADDED
package/.oxfmtrc.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"semi": true,
|
|
3
|
+
"singleQuote": false,
|
|
4
|
+
"tabWidth": 2,
|
|
5
|
+
"printWidth": 100,
|
|
6
|
+
"sortPackageJson": false,
|
|
7
|
+
"ignorePatterns": [
|
|
8
|
+
"node_modules/",
|
|
9
|
+
"dist/",
|
|
10
|
+
"dist-vsix/",
|
|
11
|
+
"coverage/",
|
|
12
|
+
"reports/",
|
|
13
|
+
".vscode-test/",
|
|
14
|
+
".superpowers/",
|
|
15
|
+
".headroom/",
|
|
16
|
+
"AGENTS.md",
|
|
17
|
+
"docs/superpowers/",
|
|
18
|
+
"test/fixtures/",
|
|
19
|
+
".claude/",
|
|
20
|
+
".codebuddy/",
|
|
21
|
+
".cursor/",
|
|
22
|
+
".gemini/",
|
|
23
|
+
".kiro/",
|
|
24
|
+
".qoder/",
|
|
25
|
+
".mcp.json",
|
|
26
|
+
".vscode/mcp.json",
|
|
27
|
+
"CLAUDE.md",
|
|
28
|
+
"CODEBUDDY.md",
|
|
29
|
+
"GEMINI.md",
|
|
30
|
+
"QODER.md",
|
|
31
|
+
".cursorrules",
|
|
32
|
+
".windsurfrules",
|
|
33
|
+
"opencode.jsonc",
|
|
34
|
+
".github/code-review-graph.instruction.md",
|
|
35
|
+
"docs/inline-sql-toolkit-architecture.html",
|
|
36
|
+
"docs/inline-sql-toolkit-architecture.visual-check.html",
|
|
37
|
+
"docs/index.html",
|
|
38
|
+
"inline-sql-toolkit-architecture.html"
|
|
39
|
+
]
|
|
40
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0 - 2026-11-06
|
|
4
|
+
|
|
5
|
+
- Feature: the CLI accepts directory arguments and processes every `.py` / `.mo.py` file below them recursively, in path order. Scans skip dot-prefixed directories, `node_modules`, `.venv`, and `__pycache__`, and never follow symbolic-link directories; a file named directly and also found in a directory is processed once. A directory with no Python files in it exits with code 2. Files named explicitly are still processed whatever their extension.
|
|
6
|
+
|
|
7
|
+
## 0.5.4 - 2026-10-10
|
|
8
|
+
|
|
9
|
+
- Docs: a skip pragma applies to every literal on its line (README).
|
|
10
|
+
- Internal: drop an unreachable check in skip pragma matching.
|
|
11
|
+
- Dependencies: bump the dev-only transitive `source-map-js` to 1.2.2 (GHSA-68fv-2mgg-jv7q).
|
|
12
|
+
|
|
3
13
|
## 0.5.3 - 2026-10-10
|
|
4
14
|
|
|
5
15
|
- 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).
|
package/README.md
CHANGED
|
@@ -143,10 +143,10 @@ The `inline-sql-toolkit` command-line tool formats Python files or standard inpu
|
|
|
143
143
|
Run directly via `npx` or install with `bun add -d inline-sql-toolkit` (or `npm install -D inline-sql-toolkit`):
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
|
-
npx inline-sql-toolkit [options] [files...]
|
|
146
|
+
npx inline-sql-toolkit [options] [files-or-directories...]
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
-
When run without file arguments, the CLI reads Python source from standard input and prints the formatted result to standard output. Notebook files (`.ipynb`) are not supported by the CLI; use the VS Code extension for Jupyter and marimo notebook cell formatting. The CLI supports standard Python source files (`.py`, `.mo.py`) and stdin.
|
|
149
|
+
When run without file arguments, the CLI reads Python source from standard input and prints the formatted result to standard output. Explicit file arguments are processed regardless of their extension. Directory arguments are scanned recursively for `.py` and `.mo.py` files, in path order; scans skip all dot-prefixed directories (including `.git` and `.jj`), `node_modules`, `.venv`, and `__pycache__`. Notebook files (`.ipynb`) are not supported by the CLI; use the VS Code extension for Jupyter and marimo notebook cell formatting. The CLI supports standard Python source files (`.py`, `.mo.py`) and stdin.
|
|
150
150
|
|
|
151
151
|
### CLI Options
|
|
152
152
|
|
|
@@ -277,6 +277,7 @@ Notes on skipping behavior:
|
|
|
277
277
|
|
|
278
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
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
|
+
- A pragma applies per line, not per literal: a trailing pragma skips every literal that ends on that line, and a dedicated pragma line skips every literal that starts on the next line. For example, `a, b = "select 1", "select 2" # inline-sql: skip` skips both literals; put them on separate lines to skip only one.
|
|
280
281
|
- Syntax highlighting is powered by TextMate grammar and is not affected by `# inline-sql: skip`. Only formatting excludes the literal.
|
|
281
282
|
- When running **Format at Cursor** on a skipped literal, the command reports `NO_SQL_CANDIDATE`.
|
|
282
283
|
- 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.
|
package/dist/cli.js
CHANGED
|
@@ -2237,7 +2237,7 @@ function isSkippedByPragma(literal, analysis) {
|
|
|
2237
2237
|
const startLine = analysis.sourceMap.vscodeFromOffset(literal.span.start).line;
|
|
2238
2238
|
const endLine = analysis.sourceMap.vscodeFromOffset(literal.span.end).line;
|
|
2239
2239
|
const { trailing, ownLine } = analysis.skipPragmaLines;
|
|
2240
|
-
return ownLine.has(startLine - 1) || trailing.has(endLine)
|
|
2240
|
+
return ownLine.has(startLine - 1) || trailing.has(endLine);
|
|
2241
2241
|
}
|
|
2242
2242
|
function discover(analysis) {
|
|
2243
2243
|
const literals = [
|
|
@@ -23007,7 +23007,7 @@ function formatProtectedSql(sql2, options) {
|
|
|
23007
23007
|
}
|
|
23008
23008
|
|
|
23009
23009
|
// src/cli.ts
|
|
23010
|
-
var USAGE = `Usage: inline-sql-toolkit [options] [files...]
|
|
23010
|
+
var USAGE = `Usage: inline-sql-toolkit [options] [files-or-directories...]
|
|
23011
23011
|
|
|
23012
23012
|
-w, --write rewrite files in place
|
|
23013
23013
|
--check exit 1 if any file would change
|
|
@@ -23022,7 +23022,103 @@ var USAGE = `Usage: inline-sql-toolkit [options] [files...]
|
|
|
23022
23022
|
--keep-functions-inline keep SUM(...) / COUNT(CASE ...) on one line
|
|
23023
23023
|
-c, --config <file> config JSON (default: nearest .inline-sql.json)
|
|
23024
23024
|
-q, --quiet do not report skipped candidates on stderr
|
|
23025
|
-
-h, --help / --version
|
|
23025
|
+
-h, --help / --version
|
|
23026
|
+
|
|
23027
|
+
Directories are scanned recursively for .py and .mo.py files. Scans skip
|
|
23028
|
+
dot-directories (including .git and .jj), node_modules, .venv, and __pycache__.`;
|
|
23029
|
+
var EXCLUDED_DIRECTORY_NAMES = /* @__PURE__ */ new Set([".git", ".jj", "node_modules", ".venv", "__pycache__"]);
|
|
23030
|
+
function isPythonSourceFile(file) {
|
|
23031
|
+
return file.endsWith(".py") || file.endsWith(".mo.py");
|
|
23032
|
+
}
|
|
23033
|
+
function isExcludedDirectory(name) {
|
|
23034
|
+
return name.startsWith(".") || EXCLUDED_DIRECTORY_NAMES.has(name);
|
|
23035
|
+
}
|
|
23036
|
+
function trimTrailingSeparators(path) {
|
|
23037
|
+
let trimmedPath = path;
|
|
23038
|
+
const rootLength = (0, import_node_path.parse)((0, import_node_path.resolve)(path)).root.length;
|
|
23039
|
+
while (trimmedPath.length > rootLength && (trimmedPath.endsWith(import_node_path.sep) || import_node_path.sep !== "/" && trimmedPath.endsWith("/"))) {
|
|
23040
|
+
trimmedPath = trimmedPath.slice(0, -1);
|
|
23041
|
+
}
|
|
23042
|
+
return trimmedPath;
|
|
23043
|
+
}
|
|
23044
|
+
function collectPythonFiles(directory) {
|
|
23045
|
+
const pendingDirectories = [directory];
|
|
23046
|
+
const pythonFiles = [];
|
|
23047
|
+
while (pendingDirectories.length > 0) {
|
|
23048
|
+
const currentDirectory = pendingDirectories.pop();
|
|
23049
|
+
if (currentDirectory === void 0) continue;
|
|
23050
|
+
for (const entry of (0, import_node_fs.readdirSync)(currentDirectory, { withFileTypes: true })) {
|
|
23051
|
+
const entryPath = (0, import_node_path.join)(currentDirectory, entry.name);
|
|
23052
|
+
if (entry.isDirectory()) {
|
|
23053
|
+
if (!isExcludedDirectory(entry.name)) pendingDirectories.push(entryPath);
|
|
23054
|
+
continue;
|
|
23055
|
+
}
|
|
23056
|
+
if (entry.isFile() && isPythonSourceFile(entryPath)) {
|
|
23057
|
+
pythonFiles.push(entryPath);
|
|
23058
|
+
continue;
|
|
23059
|
+
}
|
|
23060
|
+
if (entry.isSymbolicLink() && isPythonSourceFile(entryPath)) {
|
|
23061
|
+
if ((0, import_node_fs.existsSync)(entryPath) && (0, import_node_fs.statSync)(entryPath).isFile()) pythonFiles.push(entryPath);
|
|
23062
|
+
}
|
|
23063
|
+
}
|
|
23064
|
+
}
|
|
23065
|
+
return pythonFiles.sort((left, right) => left < right ? -1 : left > right ? 1 : 0);
|
|
23066
|
+
}
|
|
23067
|
+
function expandFileArguments(positionals) {
|
|
23068
|
+
const files = [];
|
|
23069
|
+
const seenAbsolutePaths = /* @__PURE__ */ new Set();
|
|
23070
|
+
function addFile(file) {
|
|
23071
|
+
const absolutePath = (0, import_node_path.resolve)(file);
|
|
23072
|
+
if (seenAbsolutePaths.has(absolutePath)) return;
|
|
23073
|
+
seenAbsolutePaths.add(absolutePath);
|
|
23074
|
+
files.push(file);
|
|
23075
|
+
}
|
|
23076
|
+
for (const positional of positionals) {
|
|
23077
|
+
let fileInfo;
|
|
23078
|
+
try {
|
|
23079
|
+
fileInfo = (0, import_node_fs.lstatSync)(trimTrailingSeparators(positional));
|
|
23080
|
+
} catch (err) {
|
|
23081
|
+
return {
|
|
23082
|
+
ok: false,
|
|
23083
|
+
message: `inline-sql-toolkit: cannot read file: ${positional}: ${err.message}`
|
|
23084
|
+
};
|
|
23085
|
+
}
|
|
23086
|
+
let isDirectory = fileInfo.isDirectory();
|
|
23087
|
+
if (fileInfo.isSymbolicLink()) {
|
|
23088
|
+
try {
|
|
23089
|
+
isDirectory = (0, import_node_fs.statSync)(positional).isDirectory();
|
|
23090
|
+
} catch {
|
|
23091
|
+
}
|
|
23092
|
+
}
|
|
23093
|
+
if (!isDirectory) {
|
|
23094
|
+
addFile(positional);
|
|
23095
|
+
continue;
|
|
23096
|
+
}
|
|
23097
|
+
if (fileInfo.isSymbolicLink()) {
|
|
23098
|
+
return {
|
|
23099
|
+
ok: false,
|
|
23100
|
+
message: `inline-sql-toolkit: no .py or .mo.py files found in directory: ${positional}`
|
|
23101
|
+
};
|
|
23102
|
+
}
|
|
23103
|
+
let discoveredFiles;
|
|
23104
|
+
try {
|
|
23105
|
+
discoveredFiles = collectPythonFiles(positional);
|
|
23106
|
+
} catch (err) {
|
|
23107
|
+
return {
|
|
23108
|
+
ok: false,
|
|
23109
|
+
message: `inline-sql-toolkit: cannot read directory: ${positional}: ${err.message}`
|
|
23110
|
+
};
|
|
23111
|
+
}
|
|
23112
|
+
if (discoveredFiles.length === 0) {
|
|
23113
|
+
return {
|
|
23114
|
+
ok: false,
|
|
23115
|
+
message: `inline-sql-toolkit: no .py or .mo.py files found in directory: ${positional}`
|
|
23116
|
+
};
|
|
23117
|
+
}
|
|
23118
|
+
for (const file of discoveredFiles) addFile(file);
|
|
23119
|
+
}
|
|
23120
|
+
return { ok: true, files };
|
|
23121
|
+
}
|
|
23026
23122
|
function printError(message) {
|
|
23027
23123
|
process.stderr.write(`${message}
|
|
23028
23124
|
`);
|
|
@@ -23212,8 +23308,13 @@ function runCli(argv) {
|
|
|
23212
23308
|
process.stdout.write(output);
|
|
23213
23309
|
return 0;
|
|
23214
23310
|
}
|
|
23311
|
+
const expanded = expandFileArguments(positionals);
|
|
23312
|
+
if (!expanded.ok) {
|
|
23313
|
+
printError(expanded.message);
|
|
23314
|
+
return 2;
|
|
23315
|
+
}
|
|
23215
23316
|
const tasks = [];
|
|
23216
|
-
for (const file of
|
|
23317
|
+
for (const file of expanded.files) {
|
|
23217
23318
|
let input;
|
|
23218
23319
|
try {
|
|
23219
23320
|
input = (0, import_node_fs.readFileSync)(file, "utf8");
|
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.
|
|
14
|
+
"version": "0.6.0",
|
|
15
15
|
"icon": "icon.png",
|
|
16
16
|
"type": "module",
|
|
17
17
|
"bin": {
|
|
@@ -161,9 +161,9 @@
|
|
|
161
161
|
"@eslint/js": "10.0.1",
|
|
162
162
|
"@types/node": "20.19.43",
|
|
163
163
|
"@types/vscode": "1.95.0",
|
|
164
|
-
"@vitest/coverage-v8": "4.1.
|
|
164
|
+
"@vitest/coverage-v8": "4.1.12",
|
|
165
165
|
"@vscode/test-electron": "3.1.0",
|
|
166
|
-
"@vscode/vsce": "
|
|
166
|
+
"@vscode/vsce": "4.0.0",
|
|
167
167
|
"esbuild": "0.28.1",
|
|
168
168
|
"eslint": "10.7.0",
|
|
169
169
|
"eslint-plugin-simple-import-sort": "14.0.0",
|
|
@@ -172,16 +172,18 @@
|
|
|
172
172
|
"prettier": "3.9.6",
|
|
173
173
|
"typescript": "5.9.3",
|
|
174
174
|
"typescript-eslint": "8.65.0",
|
|
175
|
-
"vitest": "4.1.
|
|
175
|
+
"vitest": "4.1.12",
|
|
176
176
|
"yaml": "2.9.0"
|
|
177
177
|
},
|
|
178
178
|
"overrides": {
|
|
179
|
+
"@azure/msal-node": "7.1.0",
|
|
179
180
|
"brace-expansion": "5.0.12",
|
|
180
|
-
"fast-uri": "3.1.
|
|
181
|
+
"fast-uri": "3.1.9",
|
|
182
|
+
"glob": "14.0.3",
|
|
181
183
|
"js-yaml": "4.3.2",
|
|
182
184
|
"nanoid": "3.3.18",
|
|
183
185
|
"postcss": "8.5.23",
|
|
184
|
-
"qs": "6.16.
|
|
185
|
-
"undici": "7.
|
|
186
|
+
"qs": "6.16.1",
|
|
187
|
+
"undici": "7.30.1"
|
|
186
188
|
}
|
|
187
189
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# format-check.sh - CI gate for the fleet-wide format/lint tool mapping.
|
|
3
|
+
#
|
|
4
|
+
# Runs the same tools as the post-edit dispatcher (agents-env:
|
|
5
|
+
# ~/.agents/global/format-file) in check mode over the files given as
|
|
6
|
+
# arguments, or over all git-tracked files when called without arguments.
|
|
7
|
+
#
|
|
8
|
+
# - Path prefixes listed in .formatignore (one per line) are skipped.
|
|
9
|
+
# - Markdown is not gated yet: oxfmt's Markdown output still diverges
|
|
10
|
+
# from this repo's Prettier-formatted docs.
|
|
11
|
+
# - Lint warnings are printed but do not fail the gate; errors do.
|
|
12
|
+
set -u
|
|
13
|
+
root=$(git rev-parse --show-toplevel) || exit 1
|
|
14
|
+
cd "$root" || exit 1
|
|
15
|
+
|
|
16
|
+
if [ $# -gt 0 ]; then
|
|
17
|
+
files="$*"
|
|
18
|
+
else
|
|
19
|
+
files=$(git ls-files)
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
ignored() {
|
|
23
|
+
[ -f .formatignore ] || return 1
|
|
24
|
+
while IFS= read -r pat; do
|
|
25
|
+
case "$pat" in
|
|
26
|
+
'' | \#*) continue ;;
|
|
27
|
+
esac
|
|
28
|
+
case "$1" in
|
|
29
|
+
"$pat"*) return 0 ;;
|
|
30
|
+
esac
|
|
31
|
+
done < .formatignore
|
|
32
|
+
return 1
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fail=0
|
|
36
|
+
for f in $files; do
|
|
37
|
+
[ -f "$f" ] || continue
|
|
38
|
+
if ignored "$f"; then continue; fi
|
|
39
|
+
case "$f" in
|
|
40
|
+
*.py | *.pyi)
|
|
41
|
+
inline-sql-toolkit --check -q "$f" || fail=1
|
|
42
|
+
ruff format --check "$f" || fail=1
|
|
43
|
+
ruff check "$f" || fail=1
|
|
44
|
+
ty check "$f" || fail=1
|
|
45
|
+
;;
|
|
46
|
+
*.js | *.jsx | *.ts | *.tsx | *.mjs | *.cjs | *.mts | *.cts | *.vue | *.svelte)
|
|
47
|
+
oxfmt --check "$f" || fail=1
|
|
48
|
+
oxlint "$f" || fail=1
|
|
49
|
+
;;
|
|
50
|
+
*.json | *.jsonc | *.json5 | *.yaml | *.yml | *.toml | *.css | *.scss | *.less | *.html | *.graphql | *.gql)
|
|
51
|
+
oxfmt --check "$f" || fail=1
|
|
52
|
+
;;
|
|
53
|
+
*.sql)
|
|
54
|
+
sql-template-formatter --check "$f" || fail=1
|
|
55
|
+
;;
|
|
56
|
+
esac
|
|
57
|
+
done
|
|
58
|
+
exit $fail
|