typescript

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package typescript — body_walk.go implements P3 of the TS parser: statement-level call extraction inside function/method bodies.

Before P3 the TS parser only emitted file-level declarations (Class / Interface / Function / Method / Decorator / TypeAlias / Enum / Import). Function bodies were unparsed, so cross-symbol call edges were absent from the TS portion of the graph — the 2026-05-09 graphify-comparison audit flagged this as the largest accuracy gap on the TS axis.

V0 scope: emit `calls` Pending refs anchored on the smallest enclosing Function/Method node for each call_expression. Pass-2 Resolve unions these by callee Name (same idiom Go's pending_refs queue uses pre-1.7).

Out of scope (deferred):

  • statement-level node emission (CallSite / IfStmt / LoopStmt / ReturnStmt / SwitchStmt) — Go has these via tree-sitter walks too; a follow-up TS pass can mirror that without changing the resolution contract here.
  • type-aware dispatch classification (invokes + dispatch_kind) — would require a TS LSP server embedded in CKG. Track C did this for Go via go/packages.Load; TS has no equivalent in-process surface today.
  • field reads/writes — captured by a separate `member_expression` query if the audit shows demand.

Package typescript — distributed.go implements W1 of schema 1.9 (CKS G5 Distributed cross-language interop expansion): TypeScript HTTP server endpoint detection. Mirrors the Go parser's distributed.go semantics so graph traversal can answer cross-language queries

TS Function ← listens_on → Endpoint ← listens_on ← Go Method

using the SAME Endpoint qname format (`http:METHOD /route`) and the SAME edge type (`listens_on`). §6.2 of docs/design/schema-1.9-spec.md elected option (B) — reuse `listens_on`, distinguish languages via the Endpoint node's `language` field (here always "ts").

V0 detection patterns (string-literal routes only — variables / concat are flagged INFERRED with a "<computed>" sentinel):

  1. Express / Koa: `app.get('/path', handler)`, `router.post('/path', ...)`, etc.
  2. Fastify: `fastify.get('/path', ...)`, `fastify.route({ method, url, handler })`
  3. Hono: `app.get('/path', c => ...)` (fluent API)
  4. Next.js App Router: file path `app/api/.../route.ts` with `export async function GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS`.

Out of scope (deferred):

  • Pages Router (`pages/api/*.ts` default export).
  • Computed routes beyond INFERRED placeholder (no const-fold).
  • Per-framework guard: receiver-type confirmation requires a TS LSP server which CKG doesn't embed. Detection is name-based ("call to a method whose name is an HTTP verb") — false positives possible on unrelated APIs that happen to use the same verb names.

Package typescript — grpc_client.go implements W3c of schema 1.9 (CKS G5 Distributed): TypeScript gRPC-web / Connect-web client detection. Companion to internal/parse/golang/grpc.go (W3b, Go server + client) — the two together let graph traversal answer "TS Func → grpc_calls → Endpoint ← grpc_listens_on ← Go Method" in a monorepo.

Detection patterns (V0 — AST-only, all INFERRED per §6.5 (c)):

  1. Generated client class instantiation + method call

    const client = new UserServiceClient(host) client.getUser(req, callback)

    The local stub variable is tracked; each subsequent `<stub>.method(...)` emits one grpc_calls edge to a placeholder Endpoint with qname `grpc:UserService.GetUser`.

  2. grpc-web unary descriptor call

    grpc.unary(EchoService.Echo, { request, host, onEnd })

    The first argument is a member_expression `Service.Method`; emits one grpc_calls edge.

  3. Connect-web / Connect-ES promise client

    const client = createPromiseClient(GreetService, transport) const client = createClient(GreetService, transport) await client.sayHello(req)

    The factory call's first argument is the service identifier; the return value is the stub. Subsequent `<stub>.method(...)` emits one grpc_calls edge per call site.

Each detection emits an AMBIGUOUS placeholder Endpoint (Language "external") and an `grpc_calls` edge (INFERRED) from the enclosing TS Function to the placeholder. The placeholder lives in a distinct ID space from the real server-side Endpoints emitted by Go W3b's `pb.RegisterXXXServer` pass, so cross-language resolution stays in placeholder form until a future linker pass merges by qname suffix (mirroring the §6.5 V0 limitation already documented for Go).

Per §6.5 (c) — typesInfo is unavailable in tree-sitter parses, so every TS gRPC call edge is INFERRED.

Pattern A (`new <Svc>Client(host)`) is gated on a file-scoped import-path heuristic: at least one import from `grpc-web`, `@improbable-eng/grpc-web`, `@bufbuild/connect-web`, `@connectrpc/connect`, `nice-grpc`, or any path matching `*grpc*` must be present, otherwise the suffix `*Client` is far too common (RedisClient / PrismaClient / ApolloClient / HttpClient / S3Client / KafkaClient / MongoClient / ElasticsearchClient / ApiClient) to be treated as a gRPC stub. This was raised by W3c code-review as Important #1 (2026-05-11) — the prior implementation matched `*Client` unconditionally and would have produced AMBIGUOUS placeholders for every non-gRPC client in a real monorepo.

Patterns B (`createPromiseClient` / `createClient`) and C (`grpc.unary(Service.Method, ...)`) carry distinctive function names and are NOT gated — their signal-to-noise ratio is high enough that false positives in real code are vanishingly rare.

Out of scope (deferred):

  • nice-grpc, twirp, ts-proto generated clients — same shape as pattern 1; can fold in incrementally.
  • Streaming methods (server-streaming, client-streaming, bidi) — emitted identically to unary in V0; stream semantics are not modelled.
  • Method-name camelCase ↔ proto PascalCase mismatch — V0 emits the observed JS method name (camelCase). Linker pass can normalise against proto Method nodes later.

Package typescript — http_client.go implements W2 of schema 1.9 (CKS G5 Distributed cross-language interop expansion): TypeScript HTTP client detection. Companion to distributed.go (server-side W1) — the two together let graph traversal answer "TS Func → http_calls → Endpoint ← listens_on ← Go Method" in a monorepo.

Detection patterns (V0 — string-literal URLs only):

  1. fetch('/api/x') → method=GET (default)
  2. fetch('/api/x', { method: 'POST' }) → method extracted from options object
  3. axios.get('/api/x', ...) → method=GET axios.post / put / delete / patch / head → same pattern
  4. axios('/api/x', { method, url }) → method from options axios({ method, url }) → both from options axios.request({ method, url }) → same
  5. useSWR('/api/x', fetcher) → method=* (any) per §6.9 "method unknown"
  6. useQuery({ url: '/api/x' }) → method=* (any). queryKey['/api/x'] is skipped — too ambiguous in V0.

Each detection emits an AMBIGUOUS placeholder Endpoint node + an `http_calls` edge from the enclosing TS Function to the placeholder. The link pass (internal/link/http_match.go) then either rewires the edge to a real server-side Endpoint (cascade: specific verb → wildcard) or keeps the placeholder as an external-API marker (§6.3 (B), §6.9).

Out of scope (deferred):

  • ky.get/post, wretch, superagent — same shape as axios; can fold in once V0 stabilises.
  • Template-string URLs (`${base}/users`) — INFERRED with route placeholder.
  • Dynamic methods (axios[verb]('/x')) — would need const-fold.

Package typescript implements the CKG parser for .ts/.tsx/.js/.jsx (spec §4.6.2).

Package typescript — statements.go emits Pass-1 statement-level nodes from inside TS/JS function bodies, mirroring the Go parser's statements.go (internal/parse/golang/statements.go). Five kinds:

  • IfStmt ← `if_statement`
  • LoopStmt ← `for_statement` / `for_in_statement` / `for_of_statement` / `while_statement` / `do_statement` (SubKind = "for" / "for-in" / "for-of" / "while" / "do")
  • SwitchStmt ← `switch_statement`
  • ReturnStmt ← `return_statement`
  • CallSite ← `call_expression`

Each node attaches to its enclosing Function / Method via a `contains` edge — same shape Go's appendLogicBlockPos produces. CallSite nodes additionally serve as the SrcID for the cross-file PendingRef that the Pass-2 Resolve consumes, mirroring the Go pattern where a `Function -> contains -> CallSite -> calls -> Method` chain is the canonical representation. This replaces the pre-existing body_walk.go-emitted PendingRefs that were anchored on the enclosing Function — keeping the schema consistent across languages so viewer/api code can treat "what calls X" the same way regardless of source language.

Out of scope (deferred — would mirror more of the Go pass):

  • Goroutine / channel / mutex emit (no equivalent runtime in TS).
  • timeout_path / cancellation_path self-loops (no AbortController pattern detection yet — could land separately).
  • dispatch_kind classification (closure/func_value/method_value) — TS has no in-process type system; everything stays as static `calls` until a TS LSP server is embedded.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser implements parse.Parser for TypeScript / JavaScript source.

func New

func New(srcRoot string) *Parser

New returns a Parser rooted at srcRoot (used for relative file paths).

func (*Parser) Extensions

func (p *Parser) Extensions() []string

Extensions reports the file extensions this parser handles.

func (*Parser) ParseFile

func (p *Parser) ParseFile(path string, src []byte) (*parse.ParseResult, error)

ParseFile runs Pass 1 over a single TS/JS source file.

func (*Parser) Resolve

func (p *Parser) Resolve(results []*parse.ParseResult) (*parse.ResolvedGraph, error)

Resolve unions per-file results and emits cross-file edges from PendingRef queues. V0 cross-file resolution is name-based — TS has no in-process type system the way Go does (Track C used go/packages), so we lean on three signals to keep the precision/recall trade-off honest:

  1. **Caller-file locality**. If the candidate set contains a node in the SAME file as the caller, prefer those — TS scoping rules mean a same-file `Foo()` is overwhelmingly the local Foo.

  2. **Confidence reflects ambiguity**. - exactly one candidate (after the locality filter) → INFERRED. - 2+ candidates → AMBIGUOUS, picking the highest-PageRank as the dst so the edge still points somewhere reasonable, but flagged so downstream consumers can de-rank or re-review.

  3. **No cross-axis pollution**. Only Function / Method / Class definitions populate the byName index — Imports / Decorators / Enum members never become call targets even when the callee name accidentally matches one. (graphify's `_cross_language` downgrade tackles the same false-positive class for its multi-language extractor; CKG's TS pass is single-language so we don't need that specific filter, but the spirit — refuse low-quality matches — is the same.)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL