Supported Languages
Semantic analysis is currently supported for JavaScript/TypeScript and
Python only. For other languages, the semantic methods return no-op
results (null for definitions, empty arrays for references).
Analysis Modes
Semantic analysis operates in two modes, each with different performance and accuracy trade-offs:File Scope (Default)
Single-file analysis that processes symbols within the current file only. This mode is fast and requires no additional configuration. Best for:- Quick analysis of local variables
- Single-file transformations
- Dry runs and exploratory analysis
- Cannot resolve cross-file imports
- Cannot find references in other files
Workspace Scope
Workspace-wide analysis that resolves cross-file imports and finds references across your entire project. This mode requires specifying a workspace root. Best for:- Renaming symbols across files
- Finding all usages of exported functions
- Dependency analysis and migration codemods
- Workspace root path must be specified
- Files must be processed (indexed) before cross-file queries work
API Reference
node.definition(options?)
Get the definition location for the symbol at this node’s position.
Returns an object containing the definition node, its root, and the kind of
definition, or null if not found.
'local'— Definition is in the same file (local variable, function, class, etc.)'import'— Definition traced to an import statement, but module couldn’t be resolved (e.g., external package)'external'— Definition resolved to a different file in the workspace
- No semantic provider is configured
- No symbol is found at this position
When a symbol comes from an unresolved import
(e.g.,
import x from "some-external-module"), definition() now returns the import statement
with kind: 'import' instead of returning null. This allows you to at least
trace the symbol back to where it was imported.node.references()
Find all references to the symbol at this node’s position.
Returns an array of file references, grouped by file.
- No semantic provider is configured
- No symbol is found at this position
In file scope mode,
references() only searches the current file. In
workspace scope mode, it searches all indexed files in the workspace.root.write(content)
Write content to a file obtained via definition() or references(). This method allows cross-file editing within a single codemod execution.
Writes the provided content to the file and updates the semantic provider’s
cache.
- Called on the current file being processed (use
returninstead) - The file has no path
- The write operation fails
Using Semantic Analysis
Via Workflow Configuration (Recommended)
The recommended way to use semantic analysis is through workflow files. Create aworkflow.yaml that references your codemod script:
Configure semantic analysis mode. Can be:
"file"— Single-file analysis (default)"workspace"— Workspace-wide analysis using the target path{ mode: "workspace", root: "./path" }— Workspace-wide with custom root
Path to the workflow YAML file.
Path to the target directory containing files to transform.
Via CLI Commands
For quick testing or simple use cases, you can also use thejssg CLI directly:
- jssg run
- jssg test
Enable workspace-wide semantic analysis using the provided path as the workspace root.
Examples
Renaming a Utility Function Across Files (TypeScript)
This example renamesformatDate to formatDateTime across a multi-file TypeScript project.
Source codebase:
Finding Usages of a Python Class
Analyze how a class is used across a Python project without making changes. Source codebase:Tracing External Module Imports
Find where external dependencies are imported whennode_modules isn’t available.
Source codebase:
When a symbol comes from an unresolved import (e.g.,
import x from "some-external-module"),
definition() returns the import statement with kind: 'import'. This allows you to trace
symbols back to their import source even when the module can’t be resolved or the semantic
mode is set to file scope.Cross-File Editing with Definition Lookup
Rename a constant and update all files that import it. Source codebase:When you call
write() on an SgRoot obtained from definition() or
references(), the semantic provider’s cache is automatically updated. This
ensures subsequent semantic queries reflect the changes.Best Practices
Use file scope for single-file transformations
Use file scope for single-file transformations
File scope analysis is faster and doesn’t require workspace configuration. Use it when your codemod only needs to understand symbols within a single file.
workflow.yaml
Handle null/empty results gracefully
Handle null/empty results gracefully
Semantic analysis may return null or empty results for various reasons. Always check return values:
Check file ownership before editing
Check file ownership before editing
When processing references across files, verify you’re editing the correct file:
Troubleshooting
Semantic methods return null/empty
Semantic methods return null/empty
Possible causes:
- No semantic analysis configured in workflow (add
semantic_analysis: workspace) - The language isn’t supported (only JavaScript/TypeScript and Python)
- The symbol couldn’t be resolved (external library, syntax error)
Cross-file references not found
Cross-file references not found
Possible causes:Then run:
- Using file scope mode instead of workspace scope
- The target file hasn’t been indexed yet
- Import resolution failed
workflow.yaml
Performance issues with large workspaces
Performance issues with large workspaces
Tips:
- Start with file scope for initial development
- Use workspace scope only when cross-file analysis is needed
- Consider running workflows on subsets of your codebase by targeting specific directories