Documentation
¶
Overview ¶
Package jsprogram defines the deterministic, source-only semantic facts used by JavaScript/TypeScript value-flow taint. It is the JS/TS twin of pythonprogram: the model is parser-independent, tree-sitter is confined to the synapse-ast infrastructure sidecar, and every document is validated here before a use case trusts it. The differences from Python are language-level: `$` is a legal identifier character, modules are identified by their source PATH (not a dotted package name), imports carry a JS ImportKind, and symbol ids use a "js:" prefix.
Index ¶
- Constants
- func CanonicalSymbolID(module, qualified string) string
- func ExternalSymbolID(specifier, export string) string
- func ExternalSymbolPrefix(specifier string) string
- type Argument
- type Assignment
- type Call
- type CallResolutionStatus
- type CoverageGap
- type Document
- type EntrypointHint
- type GapKind
- type Import
- type ImportKind
- type Module
- type Parameter
- type ParameterKind
- type Position
- type Reference
- type ReferenceKind
- type Resolution
- type ResolvedCall
- type Return
- type Symbol
- type SymbolKind
- type Value
- type ValueFlow
- type ValueFlowKind
- type ValueKind
Constants ¶
const (
// SchemaVersion is the only semantic-facts wire version this build understands.
SchemaVersion = 1
)
Variables ¶
This section is empty.
Functions ¶
func CanonicalSymbolID ¶
CanonicalSymbolID builds the stable id for a JS symbol: "js:" + module path + ":" + qualified name.
func ExternalSymbolID ¶
ExternalSymbolID is the canonical call-graph node id for a third-party export a first-party call targets: "jsnpm:" + import specifier + ":" + export path. A consumer (a reachability analyzer) reconstructs it, or matches ExternalSymbolPrefix, to ask whether first-party code reaches a call into that package.
func ExternalSymbolPrefix ¶
ExternalSymbolPrefix is the id prefix shared by every external node for one import specifier, so a consumer can match all calls into a package without reconstructing each export path.
Types ¶
type Argument ¶
type Argument struct {
Spread bool `json:"spread,omitempty"`
Value Reference `json:"value"`
ValueID string `json:"value_id,omitempty"`
Pos Position `json:"position,omitempty"`
}
Argument is one positional or spread call argument. Spread values carry Spread=true.
type Assignment ¶
type Assignment struct {
ScopeID string `json:"scope_id"`
Targets []Reference `json:"targets"`
TargetIDs []string `json:"target_ids,omitempty"`
Value Reference `json:"value"`
ValueID string `json:"value_id,omitempty"`
Pos Position `json:"position"`
}
Assignment captures a binding/value relationship without retaining expression text.
type Call ¶
type Call struct {
ID string `json:"id"`
CallerID string `json:"caller_id"`
Callee Reference `json:"callee"`
Arguments []Argument `json:"arguments,omitempty"`
ResultID string `json:"result_id,omitempty"`
ReceiverValueID string `json:"receiver_value_id,omitempty"`
Pos Position `json:"position"`
Await bool `json:"await,omitempty"`
New bool `json:"new,omitempty"` // a `new X(...)` constructor call
}
Call is one syntactic call (or `new`) expression owned by CallerID. Callee is a name/member reference when statically expressible, otherwise ReferenceUnknown; the extractor then also records a coverage gap (GapUnresolvedCall) so absence is not read as proof. Validate stays lenient about this pairing on purpose: a valid source file must never have its whole facts document rejected, so a missing gap is not an error.
type CallResolutionStatus ¶
type CallResolutionStatus string
CallResolutionStatus records whether one syntactic call has a unique semantic target. Ambiguous calls retain every conservative candidate but make a negative (not-reached) proof incomplete.
const ( CallResolved CallResolutionStatus = "resolved" CallExternal CallResolutionStatus = "external" CallAmbiguous CallResolutionStatus = "ambiguous" CallUnresolved CallResolutionStatus = "unresolved" )
type CoverageGap ¶
type CoverageGap struct {
Kind GapKind `json:"kind"`
SymbolID string `json:"symbol_id,omitempty"`
Detail string `json:"detail,omitempty"`
Pos Position `json:"position"`
}
CoverageGap is an explicit reason a complete negative is unsafe. Detail is a trusted closed label.
type Document ¶
type Document struct {
SchemaVersion int `json:"schema_version"`
Modules []Module `json:"modules"`
Symbols []Symbol `json:"symbols"`
Imports []Import `json:"imports"`
Calls []Call `json:"calls"`
Assignments []Assignment `json:"assignments"`
Returns []Return `json:"returns"`
Values []Value `json:"values"`
Flows []ValueFlow `json:"flows"`
Entrypoints []EntrypointHint `json:"entrypoint_hints"`
CoverageGaps []CoverageGap `json:"coverage_gaps"`
FilesSeen int `json:"files_seen"`
FilesParsed int `json:"files_parsed"`
NodesSeen int `json:"nodes_seen"`
Truncated bool `json:"truncated"`
}
Document is the complete versioned facts result for one source root.
func (*Document) SortCanonical ¶
func (d *Document) SortCanonical()
SortCanonical makes serialization and downstream graph construction independent of map/parser order.
type EntrypointHint ¶
type EntrypointHint struct {
SymbolID string `json:"symbol_id"`
Kind string `json:"kind"`
Pos Position `json:"position"`
}
EntrypointHint is a syntactic framework/application entrypoint cue.
type GapKind ¶
type GapKind string
GapKind is a closed reason code explaining why absence cannot be treated as proof.
const ( GapParseRecovery GapKind = "parse_recovery" GapDynamicImport GapKind = "dynamic_import" GapDynamicExecution GapKind = "dynamic_execution" GapUnresolvedImport GapKind = "unresolved_import" GapUnresolvedCall GapKind = "unresolved_call" GapUnresolvedValue GapKind = "unresolved_value" GapDynamicAttribute GapKind = "dynamic_attribute" GapBudget GapKind = "budget" GapUnreadable GapKind = "unreadable" )
type Import ¶
type Import struct {
ScopeID string `json:"scope_id"`
Kind ImportKind `json:"kind"`
Module string `json:"module"`
Name string `json:"name,omitempty"` // imported binding name (a named import's original name, or "default")
Alias string `json:"alias,omitempty"` // the local binding introduced in this module
Pos Position `json:"position"`
}
Import records one import/require binding. Module is the specifier ("express", "./util", "@scope/pkg").
type ImportKind ¶
type ImportKind string
ImportKind records how a binding entered the module. Together with Module (the specifier) it lets the taint catalog match a sink/source to its package without resolving the module graph.
const ( ImportNamed ImportKind = "named" // import { a as b } from 'm' ImportDefault ImportKind = "default" // import d from 'm' ImportNamespace ImportKind = "namespace" // import * as ns from 'm' ImportRequire ImportKind = "require" // const x = require('m') ImportReexport ImportKind = "reexport" // export ... from 'm' )
func (ImportKind) Valid ¶
func (k ImportKind) Valid() bool
type Module ¶
type Module struct {
Name string `json:"name"`
File string `json:"file"`
Pos Position `json:"position"`
}
Module associates a canonical module candidate (its source path without extension) with its source file.
type Parameter ¶
type Parameter struct {
Name string `json:"name"`
Kind ParameterKind `json:"kind"`
ValueID string `json:"value_id,omitempty"`
Pos Position `json:"position"`
}
Parameter is one callable parameter in declaration order.
type ParameterKind ¶
type ParameterKind string
ParameterKind preserves JS/TS argument-binding semantics without carrying annotations/default text.
const ( ParameterPositional ParameterKind = "positional" ParameterRest ParameterKind = "rest" // ...args ParameterDestructured ParameterKind = "destructured" // {a}/[a] pattern-bound name ParameterDefault ParameterKind = "default" // a = expr )
func (ParameterKind) Valid ¶
func (k ParameterKind) Valid() bool
type Position ¶
type Position struct {
File string `json:"file"`
Line int `json:"line"`
Column int `json:"column"`
}
Position is a normalized, relative source location. Column is zero-based, Line is one-based.
type Reference ¶
type Reference struct {
Kind ReferenceKind `json:"kind"`
Segments []string `json:"segments,omitempty"`
}
Reference is a safe expression summary such as ["req", "query", "id"]. No source body or literal value is retained. Literal references only carry Kind, not their value.
type ReferenceKind ¶
type ReferenceKind string
ReferenceKind describes a bounded expression shape. It intentionally excludes arbitrary source text.
const ( ReferenceName ReferenceKind = "name" ReferenceAttribute ReferenceKind = "attribute" // member access a.b.c ReferenceCall ReferenceKind = "call" ReferenceExpression ReferenceKind = "expression" ReferenceLiteral ReferenceKind = "literal" ReferenceUnknown ReferenceKind = "unknown" )
func (ReferenceKind) Valid ¶
func (k ReferenceKind) Valid() bool
type Resolution ¶
type Resolution struct {
Graph callgraph.Graph `json:"-"`
Calls []ResolvedCall `json:"calls"`
Gaps []CoverageGap `json:"coverage_gaps"`
Complete bool `json:"complete"`
}
Resolution is the pure JS/TS call-graph result. It is the twin of pythonprogram.Resolution: Graph is useful for POSITIVE (reached) evidence even when Complete is false, but a caller must require Complete before treating the absence of a path as a negative proof. Complete is false whenever the extractor left a coverage gap (a dynamic construct: computed member, eval/Function, dynamic import, with, an unresolved or ambiguous call), which is what keeps a JS negative sound in the presence of dynamic dispatch.
func Resolve ¶
func Resolve(document Document) (Resolution, error)
Resolve builds a deterministic, conservative JS/TS call graph from the source-only facts, with no filesystem or interpreter I/O. It mirrors pythonprogram.Resolve: it resolves what is unambiguous (lexical functions, class methods via receiver typing and this/super, first-party relative imports) and records a coverage gap for anything it cannot pin (an ambiguous or unresolved callee), so the Complete flag stays false unless every call was resolved over a fully-parsed tree.
type ResolvedCall ¶
type ResolvedCall struct {
CallID string `json:"call_id"`
CallerID string `json:"caller_id"`
Callees []string `json:"callees,omitempty"`
Status CallResolutionStatus `json:"status"`
Pos Position `json:"position"`
}
ResolvedCall connects a source call fact to its deterministic semantic candidates.
type Return ¶
type Return struct {
ScopeID string `json:"scope_id"`
Value Reference `json:"value"`
ValueID string `json:"value_id,omitempty"`
SlotID string `json:"slot_id,omitempty"`
Pos Position `json:"position"`
}
Return captures a function return expression summary.
type Symbol ¶
type Symbol struct {
ID string `json:"id"`
Module string `json:"module"`
QualifiedName string `json:"qualified_name"`
Name string `json:"name"`
ParentID string `json:"parent_id,omitempty"`
Kind SymbolKind `json:"kind"`
Pos Position `json:"position"`
Parameters []Parameter `json:"parameters,omitempty"`
Decorators []Reference `json:"decorators,omitempty"`
Bases []Reference `json:"bases,omitempty"` // the class's `extends` clause (at most one in JS)
Async bool `json:"async,omitempty"`
}
Symbol is a module, class, function, method, or arrow declaration.
type SymbolKind ¶
type SymbolKind string
SymbolKind identifies a JS/TS declaration that owns a lexical scope or can appear in a call graph.
const ( SymbolModule SymbolKind = "module" SymbolClass SymbolKind = "class" SymbolFunction SymbolKind = "function" SymbolMethod SymbolKind = "method" SymbolArrow SymbolKind = "arrow" // the JS analog of a Python lambda (arrow / anonymous function expression) )
func (SymbolKind) Valid ¶
func (k SymbolKind) Valid() bool
type Value ¶
type Value struct {
ID string `json:"id"`
ScopeID string `json:"scope_id"`
Kind ValueKind `json:"kind"`
Name string `json:"name,omitempty"`
Ref Reference `json:"reference"`
Pos Position `json:"position"`
}
Value is one stable value slot. Ref carries only a bounded semantic shape; source text is never kept.
type ValueFlow ¶
type ValueFlow struct {
FromID string `json:"from_id"`
ToID string `json:"to_id"`
Kind ValueFlowKind `json:"kind"`
Pos Position `json:"position"`
}
ValueFlow says a value can propagate from one slot to another inside the same JS function.
type ValueFlowKind ¶
type ValueFlowKind string
ValueFlowKind is a closed intra-procedural propagation operation emitted by the sidecar.
const ( FlowExpression ValueFlowKind = "expression" FlowAttribute ValueFlowKind = "attribute" FlowAssignment ValueFlowKind = "assignment" FlowReturn ValueFlowKind = "return" )
func (ValueFlowKind) Valid ¶
func (k ValueFlowKind) Valid() bool