TypeScript examples
These examples run against Zod, a TypeScript schema declaration library, and its published package zod/packages/zod. Each example calls one method of the CLDK Python SDK. A real run of CLDK 2.0.0rc7 over Zod produced every output comment on this page. A section with the 2.0 badge needs the pre-release, so install it with pip install --pre cldk. The stable release on PyPI is 1.5.0. Some examples carry no output comment, because that run did not record one.
Set up the analysis
Section titled “Set up the analysis”Clone Zod first.
git clone https://github.com/colinhacks/zod.gitThen point CLDK at the published package.
from cldk import CLDKfrom cldk.analysis import AnalysisLevel
analysis = CLDK.typescript( project_path="zod/packages/zod", analysis_level=AnalysisLevel.call_graph,)The zod/packages/zod directory holds both the v3 and the v4 source trees. A signature under one of those trees carries a src/v3 or a src/v4 prefix. The default analysis level builds the symbol table only. The call_graph level adds the caller and callee edges.
The backend reuses a cached analysis.json at any level. If an earlier run wrote that cache at the symbol-table level, pass eager=True once.
analysis = CLDK.typescript( project_path="zod/packages/zod", analysis_level=AnalysisLevel.call_graph, eager=True,)Symbol table: modules, classes, and methods
Section titled “Symbol table: modules, classes, and methods”List all modules
Section titled “List all modules”The symbol table holds one TSModule per source file. Each key is the package-relative file path with its extension.
modules = analysis.get_modules()print(len(modules), "modules")
symbol_table = analysis.get_symbol_table()for file_path in sorted(symbol_table)[:5]: print(file_path)# expected output:# 135 modules# src/compile.ts# src/index.ts# src/locales/index.ts# src/mini/index.ts# src/v3/ZodError.tsList all classes
Section titled “List all classes”A class signature is the file path without its extension, then the dotted member path.
classes = analysis.get_classes()print(len(classes), "classes")for signature in sorted(classes)[:6]: print(signature)# expected output:# 53 classes# src/v3/ZodError.ZodError# src/v3/helpers/parseUtil.ParseStatus# src/v3/types.Class# src/v3/types.ParseInputLazyPath# src/v3/types.ZodAny# src/v3/types.ZodArrayGet one class
Section titled “Get one class”Get one class by its signature. Read methods and base_classes from the TSClass that comes back.
tsclass = analysis.get_class("src/v3/ZodError.ZodError")print(tsclass.signature)print(sorted(tsclass.methods))print(tsclass.base_classes)List the fields of a class
Section titled “List the fields of a class”Get every field of one class. Each field is a TSField with a name and a type.
fields = analysis.get_fields("src/v3/types.ZodArray")for field in fields: print(field.name, field.type)Get one method
Section titled “Get one method”Get one method by the class signature and the method name. Read its source from code.
methods = analysis.get_methods_in_class("src/v3/ZodError.ZodError")name = sorted(methods)[0]
method = analysis.get_method("src/v3/ZodError.ZodError", name)print(method.signature)print(method.return_type)print(method.code)Filter classes by name pattern
Section titled “Filter classes by name pattern”Match an inclusion pattern and an exclusion pattern against the class signature.
matches = analysis.get_classes_by_criteria( inclusions=["ZodError"], exclusions=["v4"],)for signature in sorted(matches): print(signature)List imports
Section titled “List imports”Get the imports of every module. Each entry is a TSImport with the imported name and the resolved module path.
imports = analysis.get_imports()for file_path, import_list in sorted(imports.items())[:3]: print(file_path, len(import_list), "imports")Type declarations: interfaces, enums, and type aliases
Section titled “Type declarations: interfaces, enums, and type aliases”TypeScript has type declarations that Python does not have. Zod declares its error types in src/v3/ZodError.ts.
List interfaces
Section titled “List interfaces”Zod declares an interface for each kind of validation issue.
interfaces = analysis.get_interfaces()for signature in sorted(interfaces)[:4]: print(signature)# expected output:# src/v3/ZodError.ZodCustomIssue# src/v3/ZodError.ZodInvalidArgumentsIssue# src/v3/ZodError.ZodInvalidDateIssue# src/v3/ZodError.ZodInvalidEnumValueIssueList enums
Section titled “List enums”Zod declares two enums, one in each source tree.
for signature in sorted(analysis.get_enums()): print(signature)# expected output:# src/v4/classic/compat.ZodFirstPartyTypeKindTo read the members of one enum, call get_enum_members with the enum signature. Each member holds a name and a value.
for member in analysis.get_enum_members("src/v3/types.ZodFirstPartyTypeKind"): print(member.name, "=", member.value)List type aliases
Section titled “List type aliases”A type alias keeps the same signature shape as a class or an interface.
type_aliases = analysis.get_type_aliases()for signature in sorted(type_aliases)[:6]: print(signature)# expected output:# src/v3/ZodError.DenormalizedError# src/v3/ZodError.ErrorMapCtx# src/v3/ZodError.IssueData# src/v3/ZodError.StringValidation# src/v3/ZodError.ZodErrorMap# src/v3/ZodError.ZodFormattedErrorDecorators
Section titled “Decorators”Read the decorators
Section titled “Read the decorators”The backend captures each decorator with its arguments. Pass a class signature to get_class_decorators. Pass a list of decorator names to get_methods_with_decorators.
print(analysis.get_class_decorators("src/v3/types.ZodArray"))print(analysis.get_methods_with_decorators(["Get"]))Call graph: callers, callees, and reachability
Section titled “Call graph: callers, callees, and reachability”Every call-graph query needs analysis_level=AnalysisLevel.call_graph. The default level builds the symbol table only, and it resolves no call targets.
Build the call graph
Section titled “Build the call graph”The call graph is a networkx.DiGraph, and its edges point from the caller to the callee.
cg = analysis.get_call_graph()print(cg.number_of_nodes(), "nodes,", cg.number_of_edges(), "edges")# expected output:# 2255 nodes, 4610 edgesList the external targets
Section titled “List the external targets”An external symbol is a call target that the backend never analyzed. Its key is the module name and the symbol name. A runtime built-in has the module name (builtin).
externals = sorted(analysis.get_external_symbols())print(externals[:4])# expected output:# ['(builtin).abs', '(builtin).add', '(builtin).all', '(builtin).apply']Find the callers of a method
Section titled “Find the callers of a method”The result holds target_method and a list of caller_details. Each entry in caller_details holds a caller_signature and an edge with type, weight, and provenance. The provenance tuple names the resolver that found the edge.
target = sorted(analysis.get_methods_in_class("src/v3/ZodError.ZodError"))[0]
callers = analysis.get_callers( target_class_name="src/v3/ZodError.ZodError", target_method_declaration=target,)print(callers["target_method"])for detail in callers["caller_details"]: print(detail["caller_signature"], detail["edge"]["provenance"])Find the callees of a method
Section titled “Find the callees of a method”The result holds source_method and a list of callee_details, with the same edge shape.
source = sorted(analysis.get_methods_in_class("src/v3/types.ZodArray"))[0]
callees = analysis.get_callees( source_class_name="src/v3/types.ZodArray", source_method_declaration=source,)for detail in callees["callee_details"]: print(detail["callee_signature"], detail["edge"]["provenance"])Get the call graph of a class
Section titled “Get the call graph of a class”Get every call edge reachable from the methods of one class. To start from one method, pass its full signature as the second argument.
edges = analysis.get_class_call_graph("src/v3/types.ZodArray")print(len(edges), "edges")for caller, callee in edges[:4]: print(caller, "->", callee)Compute reachability
Section titled “Compute reachability”Reachability is a networkx query over the call graph. The key of a callable node is its signature, so pass the key to nx.has_path() directly.
import networkx as nx
cg = analysis.get_call_graph()
# Pick a source node and a target node from the graph itselfsource = sorted(n for n in cg.nodes if n.startswith("src/v3/types.ZodArray."))[0]target = sorted(n for n in cg.nodes if n.startswith("src/v3/ZodError.ZodError."))[0]
if nx.has_path(cg, source, target): print(" -> ".join(nx.shortest_path(cg, source, target)))Find the call paths between two callables 2.0
Section titled “Find the call paths between two callables ”reaches() and call_paths_between() take a callable name. A name matches a whole signature, or a dotted suffix of one. Each path is a list of hops, and each hop has a frm node and a to node.
methods = analysis.get_methods_in_class("src/v3/ZodError.ZodError")source = analysis.get_method("src/v3/ZodError.ZodError", sorted(methods)[0]).signaturetarget = "src/v3/ZodError.quotelessJson"
print(analysis.reaches(source, target))
result = analysis.call_paths_between(source, target)for path in result.paths: nodes = [path.hops[0].frm.callable] nodes += [hop.to.callable for hop in path.hops] print(" -> ".join(nodes))Model objects: TSClass and TSCallable
Section titled “Model objects: TSClass and TSCallable”CLDK returns typed model objects, not plain strings. The run for this page did not record the field values of these objects for Zod. For the full field list of each model, read the TypeScript API reference.
Inspect a TSClass
Section titled “Inspect a TSClass”A TSClass holds the methods, the fields, the base classes, the implemented interfaces, and the line span of a class.
tsclass = analysis.get_class("src/v3/types.ZodArray")print(tsclass.name)print(tsclass.signature)print(tsclass.base_classes)print(tsclass.start_line, "to", tsclass.end_line)Inspect a TSCallable
Section titled “Inspect a TSCallable”A TSCallable represents a function, a method, a constructor, an accessor, or an arrow function. Its kind is one of function, method, constructor, getter, setter, arrow, and function_expression.
methods = analysis.get_methods_in_class("src/v3/types.ZodArray")method = methods[sorted(methods)[0]]
print(method.kind, "->", method.return_type)print("Async:", method.is_async)print("Complexity:", method.cyclomatic_complexity)print(method.code)Read the class hierarchy
Section titled “Read the class hierarchy”Read the base classes of a class. Find the direct subclasses of a class. get_sub_classes() also accepts an interface signature. get_nested_classes() always returns [] on schema v2, because a class node has no bucket for nested types.
print(analysis.get_extended_classes("src/v3/types.ZodArray"))print(analysis.get_implemented_interfaces("src/v3/types.ZodArray"))print(list(analysis.get_sub_classes("src/v3/types.ZodAny").keys()))print(analysis.get_nested_classes("src/v3/types.ZodArray"))Source positions 2.0
Section titled “Source positions ”Locate a line
Section titled “Locate a line”locate() resolves a file path and a 1-based line number to the callable that encloses that line. The result also names the type that owns the callable, the module, and the innermost body node. If the line sits at module scope, callable is None and diagnostics holds a module_scope code.
loc = analysis.locate("src/v3/ZodError.ts", 100)print(loc.callable)print(loc.module.path)print([d.code for d in loc.diagnostics])Read the source of a callable
Section titled “Read the source of a callable”get_source() returns the source text of one callable signature.
print(analysis.get_source("src/v3/ZodError.quotelessJson"))