Skip to content

skyquery

A query tool for analyzing Starlark source code. Find function definitions, load statements, and function calls across your codebase using a simple query language.

Terminal window
go install github.com/albertocavalcante/sky/cmd/skyquery@latest
Terminal window
# List all function definitions
skyquery 'defs(//...)'
# List all load statements in a directory
skyquery 'loads(//internal/...)'
# Find functions matching a pattern
skyquery 'filter("^test_", defs(//...))'
# Output as JSON
skyquery --output=json 'defs(//...)'
# Show file locations
skyquery --output=location 'defs(//...)'
# Count results only
skyquery --output=count 'files(//...)'
FlagDescription
--outputOutput format: name, location, json, count (default: name)
--workspaceWorkspace root directory (default: .)
--keep_goingContinue on parse errors
--versionPrint version and exit

skyquery uses a simple functional query language to find elements in Starlark source files.

Target patterns specify which files to analyze:

PatternDescription
//...All files in workspace recursively
//path/...All files under path/ recursively
//path:file.starSpecific file

Find function definitions:

Terminal window
# All function definitions
skyquery 'defs(//...)'
# Functions in a specific directory
skyquery 'defs(//lib/...)'

Find load statements:

Terminal window
# All load statements
skyquery 'loads(//...)'
# Loads in BUILD files
skyquery 'loads(//...)'

Find function calls:

Terminal window
# Find all calls to 'load'
skyquery 'calls(load, //...)'
# Find all calls to 'rule'
skyquery 'calls(rule, //...)'

List matching files:

Terminal window
# Count all Starlark files
skyquery --output=count 'files(//...)'
# List all files in a directory
skyquery 'files(//internal/...)'

Filter query results by name:

Terminal window
# Find test functions
skyquery 'filter("^test_", defs(//...))'
# Find private functions
skyquery 'filter("^_", defs(//...))'
# Find functions ending with _impl
skyquery 'filter("_impl$", defs(//...))'

Outputs just the names, one per line:

Terminal window
$ skyquery 'defs(//lib/...)'
create_target
validate_inputs
helper_function

Outputs file:line: name format:

Terminal window
$ skyquery --output=location 'defs(//lib/...)'
lib/targets.star:10: create_target
lib/targets.star:25: validate_inputs
lib/utils.star:5: helper_function

Full JSON output with all details:

Terminal window
$ skyquery --output=json 'defs(//lib/...)'
{
"query": "defs(//lib/...)",
"items": [
{
"type": "def",
"name": "create_target",
"file": "lib/targets.star",
"line": 10,
"params": ["name", "srcs", "deps"],
"docstring": "Create a build target."
},
{
"type": "def",
"name": "validate_inputs",
"file": "lib/targets.star",
"line": 25,
"params": ["inputs"],
"docstring": ""
}
]
}

Outputs only the count of results:

Terminal window
$ skyquery --output=count 'defs(//...)'
42
$ skyquery --output=count 'files(//...)'
15
Terminal window
# Functions not starting with underscore
skyquery 'filter("^[^_]", defs(//...))'
Terminal window
# Find all external loads
skyquery --output=json 'loads(//...)' | jq '.items[] | select(.module | startswith("@"))'
Terminal window
# Count functions in each major directory
for dir in lib internal rules; do
count=$(skyquery --output=count "defs(//${dir}/...)")
echo "${dir}: ${count} functions"
done
Terminal window
# Get JSON and filter for empty docstrings
skyquery --output=json 'defs(//...)' | \
jq '.items[] | select(.docstring == "") | .name'
Terminal window
# Find all rule implementations
skyquery 'filter("_impl$", defs(//...))'
# Find all test functions
skyquery 'filter("^test_", defs(//...))'
# Find all setup functions
skyquery 'filter("^setup", defs(//...))'
Terminal window
# Create a markdown index of all functions
echo "# Function Index"
echo ""
skyquery --output=location 'defs(//...)' | while read line; do
file=$(echo "$line" | cut -d: -f1)
linenum=$(echo "$line" | cut -d: -f2)
name=$(echo "$line" | cut -d: -f3 | tr -d ' ')
echo "- [\`${name}\`](${file}#L${linenum})"
done
Terminal window
# In CI, compare against baseline
skyquery --output=count 'defs(//...)' > current_count.txt
diff baseline_count.txt current_count.txt || echo "Function count changed"
Terminal window
# Fail if any public function doesn't follow naming convention
bad_names=$(skyquery 'filter("^[A-Z]", defs(//...))' | wc -l)
if [ "$bad_names" -gt 0 ]; then
echo "Error: Found $bad_names functions starting with uppercase"
skyquery 'filter("^[A-Z]", defs(//...))'
exit 1
fi
- name: Generate function index
run: |
skyquery --output=json 'defs(//...)' > docs/function-index.json
Terminal window
# Instead of scanning everything:
skyquery 'defs(//...)'
# Scan specific directories:
skyquery 'defs(//lib/...)'
skyquery 'defs(//rules/...)'
Terminal window
# Don't fail on parse errors in some files
skyquery --keep_going 'defs(//...)'
Terminal window
# Run from a different directory
skyquery --workspace=/path/to/project 'defs(//...)'
CodeMeaning
0Success
1Error (invalid query, no files found, etc.)
query = function "(" args ")"
function = "defs" | "loads" | "calls" | "files" | "filter"
args = arg ("," arg)*
arg = pattern | string | query
pattern = "//" path "..."
string = "\"" chars "\""
Featureskyquerybazel query
ScopeStarlark source filesBuild graph
SpeedFast (no build)Requires loading
Function defsYesNo
Load statementsYesLimited
DependenciesNoYes
TargetsNoYes

skyquery is designed for source code analysis, not build graph queries. Use Bazel’s query for dependency analysis and skyquery for source-level analysis.