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 ADDED
@@ -0,0 +1,2 @@
1
+ # Path prefixes the format gate skips (see scripts/format-check.sh).
2
+ test/fixtures/
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) || ownLine.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 positionals) {
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.5.3",
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.11",
164
+ "@vitest/coverage-v8": "4.1.12",
165
165
  "@vscode/test-electron": "3.1.0",
166
- "@vscode/vsce": "3.9.2",
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.11",
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.8",
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.0",
185
- "undici": "7.29.1"
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