Skip to main content
CodeLLM-DevKit

codeanalyzer-typescript (cants)

A TypeScript/JavaScript static-analysis toolkit — the CLDK backend that emits the canonical schema-v2 Code Property Graph (symbol table → call graph → intraprocedural dataflow → interprocedural SDG), as analysis.json or a Neo4j property graph.

PyPI Python Release License


cants is a static analyzer for TypeScript/JavaScript built on the TypeScript compiler (via ts-morph). It produces the canonical CodeLLM-DevKit (CLDK) schema v2 — one additive Code Property Graph, built up level by level (symbol table → call graph → intraprocedural dataflow → interprocedural SDG) — as analysis.json and can project that same structure into a Neo4j property graph. It is the TypeScript backend behind CLDK, mirroring its Python and Java siblings.

The call graph is the TypeScript compiler's resolver plus a defuse linker — a deterministic, per-callable pass that backfills the edges the resolver misses (alias chains, decorator invocations, callbacks handed to library calls, parameter-flow calls) with no whole-program fixpoint. Edges keep a provenance tag (tsc / defuse / import), so you can tell the layers apart, and the output is byte-identical across runs.

Table of Contents

Features

  • Symbol table — modules, classes, interfaces, enums, type aliases, namespaces, functions, methods, variables, decorators, and JSDoc, with precise source spans.
  • Call graph — the TypeScript compiler's resolver plus Rapid Type Analysis (RTA), with phantom (external) nodes for calls into imported libraries and Node builtins.
  • Defuse linker — a deterministic per-callable pass over the resolver's leftovers: alias chains, decorator invocations, library-callback edges, and bounded interprocedural votes — validated as a strict superset of Joern's real call pairs on the reference corpus.
  • Repository-artifact layer — every non-code file (manifests, lockfiles, CI, containers, env) inventoried with flat, evidence-tagged dependencies (direct and transitive) and a ConfigKey family joined to the code that reads it via a level-graded config_use edge; see docs/skills/analyzing-cants-graphs/.
  • Neo4j output — project the analysis into a labeled property graph: a self-contained graph.cypher snapshot, or an incremental push to a live database over Bolt.
  • Versioned schema — a machine-readable, version-stamped Neo4j schema contract (--emit schema), bundled in every release and enforced by a conformance test.
  • Self-contained binary — no Bun or Node required at runtime; install via pip, Homebrew, or a one-line shell script.
  • Incremental — content-hash caching so re-analyzing (and re-loading the graph) only touches what changed.

Installation

Prerequisites

Running a prebuilt cants binary requires nothing — it is fully self-contained. To analyze a project, that project should be a normal Node/TypeScript project (so the compiler can resolve types and imports). Building cants from source requires Bun 1.0+.

Install via shell script

Download and install the prebuilt binary for your platform from the latest release:

curl --proto '=https' --tlsv1.2 -LsSf https://github.com/codellm-devkit/codeanalyzer-typescript/releases/latest/download/cants-installer.sh | sh

The installer drops cants into ~/.local/bin (override with CANTS_INSTALL_DIR) and can pin a version with CANTS_VERSION=vX.Y.Z. Supports macOS (arm64/x86_64) and Linux (x86_64/aarch64).

Install via Homebrew

brew install codellm-devkit/homebrew-tap/codeanalyzer-typescript

Install via pip (PyPI)

The wheel bundles the prebuilt, self-contained binary for your platform (no Bun or Node required):

pip install codeanalyzer-typescript
cants --help

This is also the package CLDK's Python SDK depends on to locate the analyzer backend; it exposes codeanalyzer_typescript.bin_path() and schema_path().

Build from source

# Install Bun, then:
git clone https://github.com/codellm-devkit/codeanalyzer-typescript
cd codeanalyzer-typescript
bun install
bun run build      # → dist/cants (standalone native binary)

You can also run the analyzer directly from source without compiling:

bun run start -- --input /path/to/typescript/project

Usage

cants --input /path/to/typescript/project

With no --output, the analysis is printed to stdout as compact JSON; with --output <dir> it is written to analysis.json (or graph.cypher for --emit neo4j) in that directory.

Options

Usage: cants [options]

CLDK TypeScript analyzer — emits the canonical schema-v2 CPG (symbol table →
call graph → dataflow → SDG) as analysis.json, or a Neo4j graph.

Options:
  -i, --input <path>             project root to analyze (not required for
                                 --emit schema)
  -o, --output <dir>             output directory (omit ⇒ compact output to
                                 stdout)
  --emit <target>                output target: json (analysis.json, default) |
                                 neo4j (graph.cypher or live push) | schema (the
                                 Neo4j schema.json contract) (default: "json")
  --app-name <name>              logical application name for the graph
                                 :Application anchor (default: input dir name)
  --namespace <name>             application identity namespace (default:
                                 application name)
  --neo4j-uri <uri>              push the graph to a live Neo4j over Bolt
                                 (incremental); omit to write graph.cypher (env:
                                 NEO4J_URI)
  --neo4j-user <user>            Neo4j username (default: "neo4j", env:
                                 NEO4J_USERNAME)
  --neo4j-password <password>    Neo4j password (prefer the env var; a flag is
                                 visible in shell history / process list)
                                 (default: "neo4j", env: NEO4J_PASSWORD)
  --neo4j-database <db>          Neo4j database name (env: NEO4J_DATABASE)
  -a, --analysis-level <n>       analysis depth: 1 = symbol table (default); 2 =
                                 + resolver call graph; 3 = + intraprocedural
                                 dataflow (cfg/cdg/ddg); 4 = + interprocedural
                                 SDG (param_in/param_out/summary) (default: "1")
  --graphs <list>                dataflow sections to emit, comma-separated: cfg
                                 | dfg | pdg (require -a 3) | sdg (requires -a
                                 4); default: all rungs at or below the level
  --graph-field-depth <k>        access-path depth bound (k-limit) for level-3
                                 dataflow (default: "3")
  -j, --jobs <n>                 worker parallelism for level-3 graphs (default:
                                 sequential; opt in with N ≥ 2 on large projects
                                 — each worker loads its own copy of the
                                 program)
  -t, --target-files <paths...>  restrict analysis to specific files
                                 (incremental)
  --skip-tests                   skip test trees (default)
  --include-tests                include test trees
  --eager                        force a clean rebuild instead of reusing the
                                 cache
  --lazy                         reuse the cache (default)
  --no-build                     skip dependency materialization (use a prepared
                                 node_modules)
  --no-phantoms                  disable phantom (external) nodes for
                                 imported/required library calls
  --resolve-installed            probe node_modules metadata for import→package
                                 binding (default: repo files only)
  --no-artifact-text             keep the artifact inventory but drop captured
                                 raw text
  --entrypoint-rules <yaml...>   extra entrypoint rules file(s), merged with the
                                 shipped set; repeatable
  --program <tsconfig...>        restrict the run to these programs, named by
                                 scope dir relative to --input ('<root>' for the
                                 root program); repeatable
  --list-programs                list the discovered programs, one per line, and
                                 exit
  --emit-ir                      persist this shard's graph IR for a later
                                 cross-shard stitch
  --no-repo-sections             skip artifacts/dependencies/unresolved_imports
                                 (repo-scoped; compute them once per repository,
                                 not once per shard)
  -c, --cache-dir <dir>          cache/intermediate directory
  -v, --verbose                  increase verbosity (repeatable)
  -h, --help                     display help for command

Examples

  1. Basic analysis to stdout, or to a file:

    cants --input ./my-ts-project                         # compact JSON on stdout
    cants --input ./my-ts-project --output ./out          # → ./out/analysis.json
    
  2. Emit a Neo4j snapshot, or push to a live database:

    cants --input ./my-ts-project --emit neo4j --output ./out     # → ./out/graph.cypher
    cants --input ./my-ts-project --emit neo4j \
      --neo4j-uri bolt://localhost:7687 --neo4j-user neo4j --neo4j-password secret
    
  3. Incremental analysis of specific files:

    cants --input ./my-ts-project --target-files src/a.ts src/b.ts
    
  4. Group applications in a namespace:

    cants --input ./monorepo/packages/web --app-name web --namespace monorepo
    # application id: can://monorepo/web
    # symbol_table key: src/app.ts (relative to --input)
    

    Namespace defaults to the application name. Both root segments are always present. Raw identity names are case sensitive and percent encoded; empty names, separators, control characters, and dot names are rejected. Version 2 identities require identity_version: 2 on the envelope and application anchor. Regenerate legacy output from source. Cache reuse requires the same namespace and application.

  5. Force a clean rebuild with a custom cache directory:

    cants --input ./my-ts-project --eager --cache-dir /path/to/custom-cache
    
  6. Program graphs (level 3): CFG/PDG/SDG in analysis.json:

    cants --input ./my-ts-project -a 3                    # full program_graphs section
    cants --input ./my-ts-project -a 3 --graphs cfg,pdg   # scope the emitted graphs
    

Output targets

cants builds one analysis in memory and can emit it three ways (--emit):

analysis.json (default)

The canonical schema v2 — one additive Code Property Graph: a containment tree of nodes (id / kind / span / children) with typed edge overlays. Analysis levels populate it more deeply; each level only ever adds.

{
  "schema_version": "2.0.0", "identity_version": 2, "language": "typescript", "max_level": 4, "k_limit": 3,
  "application": {
    "id": "can://<namespace>/<app>", "name": "<app>", "kind": "application",
    "identity_version": 2, "application_name": "<app>", "identity_namespace": "<namespace>",
    "symbol_table": {                     // L1: the tree, keyed by file path
      "<file>": { "kind": "module", "source": "…",
        "types":     { /* class | interface | enum | type_alias | namespace nodes */ },
        "functions": { /* callable nodes: { id, kind, span, body{}, cfg[], cdg[], ddg[], summary[] } */ },
        "fields":    { /* module-level bindings */ } } },
    "call_graph": [ /* L2: { src, dst, prov, weight } — callable → callable, can:// ids */ ],
    "param_in":   [ /* L4: actual_in → formal_in, fully-qualified can://…@local ids */ ],
    "param_out":  [ /* L4: formal_out → actual_out */ ]
  }
}

Each callable's body{} is keyed by local id (line:col, or @entry/@formal_in:N/… for synthetic vertices); intra-callable edge lists (cfg/cdg/ddg/summary) use those bare local ids, cross-callable lists use fully-qualified can://…@local ids. A single signature canonicalizer underlies every can:// id, so call edges, dataflow edges, and tree nodes all join. The full model is .claude/SCHEMA_DECISIONS.md (§ "Schema v2 migration") and the CLDK canonical-schema.md.

Dataflow (-a 3 intraprocedural, -a 4 interprocedural)

Native dependence graphs, built in-process from the same ts-morph AST (no external engine), grown into the tree (not a separate section):

  • -a 3 completes each callable's body{} with statement nodes and hangs the intra-callable edge lists cfg (exceptional control flow), cdg (control dependence), and ddg (data dependence via reaching-definitions, prov:["reaching-defs"]) on the callable.
  • -a 4 adds the synthetic @formal_in:N / @formal_out / <L>/actual_in:N / <L>/actual_out vertices, the intra-caller summary edges, and the application-scope param_in / param_out lists — the whole-program System Dependence Graph.

-a 3 implies -a 2; -a 4 implies -a 3. --graphs cfg,dfg,pdg,sdg scopes which rungs emit (cfg/dfg/pdg require -a 3, sdg requires -a 4). L1 ⊆ L2 ⊆ L3 ⊆ L4 is a monotonicity gate. Every node is addressed by its can://…@local id, so dataflow edges, call edges, and tree nodes all join.

Substrate (locked in issue #2): the CFG and reaching-definitions are hand-built from the ts-morph AST; the call-graph oracle is the provenance-merged tsc + defuse graph; aliasing is a flow-insensitive copy-alias MVP (points-to-backed propagation is a staged upgrade). Function summaries are composed bottom-up over the SCC condensation of the call graph, with k-limited access paths; module globals ride the SDG as extra parameters. The analysis is deliberately sound-leaning and over-approximate; known unsoundness (dynamic eval, reflection/monkey-patching, npm-internal effects) is recorded in .claude/SCHEMA_DECISIONS.md. The analyzer is a pure graph provider: it emits the dependence-graph substrate (CFG/PDG/SDG + summary edges) and stops — backward slicing and taint are reachability queries over the SDG that live in the frontend SDK, not here.

Parallelism (-j/--jobs). The pipeline implements the level-3 parallel execution model: stage-1–4 extraction fans out per callable over a Bun worker pool (partitioned by file) and is posted before the call-graph solve so the two overlap; summary composition runs as a Kahn-style ready-queue wavefront over the SCC condensation DAG (the SCC is the atomic unit). --jobs N output is byte-identical to --jobs 1 (node ids are span-ordered, all edge lists are collect-then-sorted, and the SCC fixpoint is a pure function of its inputs) — enforced by a differential test. It is off by default and worth opting into only on large codebases: ts-morph ASTs cannot cross the worker boundary, so each extraction worker loads its own copy of the program, which dominates the parallelizable graph math on small/mid repos (self-analysis runs 2.5× slower at -j 14). Worker failure at any stage degrades to the sequential path with a warning — never to wrong or missing output.

Levels 1/2 are unaffected: nothing in level 3 runs unless -a 3 is requested.

Neo4j graph

--emit neo4j projects the same v2 tree into a labeled property graph: every node keyed by its can:// id under a shared :CanNode merge label (+ a TS-prefixed specific kind label, e.g. :TSModule, :TSCallable), containment as TS_HAS_MODULE/TS_DECLARES/TS_HAS_METHOD/ TS_HAS_FIELD/TS_HAS_BODY_NODE edges, and the overlays (TS_CALLS, TS_CFG_NEXT, TS_CDG, TS_DDG, TS_SUMMARY, TS_PARAM_IN, TS_PARAM_OUT) as typed relationships. The graph is always full-depth — analysis levels gate the JSON path only, so combining -a/--graphs with --emit neo4j is an error:

Every node id is can://<namespace>/<app>/…, so can://<namespace>/<app> is a prefix of every node the application emits — the typescript and javascript namespaces are two segments inside it, not two top-level namespaces a consumer has to enumerate. That single prefix is what the destructive statements scope on, and :Application is keyed on the id rather than on --app-name.

  • Without --neo4j-uri — writes a self-contained graph.cypher (constraints + indexes, a scoped wipe, then batched MERGEs). Load it with cypher-shell < graph.cypher.

  • With --neo4j-uri — pushes to a live Neo4j over Bolt incrementally: only modules whose content hash changed are rewritten, and on a full run modules whose source file vanished are pruned. Every graph carries a schema_version on its :Application node.

    --eager purges this application's code nodes but not its :Artifact/:ConfigKey nodes, which are shared with the sibling analyzers. An --eager full run (no --target-files) reconciles them instead, so deleted or renamed files and removed dependencies within the selected scope leave nothing stale. Legacy roots and other namespaces remain outside this scope. TypeScript-owned artifact edges (HAS_ARTIFACT, DECLARES_DEPENDENCY/LOCKS to pkg:npm/…, TS_PROVIDES, TS_USES_CONFIG, TS_READS_CONFIG_UNRESOLVED, TS_UNRESOLVED_IMPORT) are rebuilt. An :Artifact or :ConfigKey the run no longer emits loses its :TSCanNode label. An artifact is then deleted only if no other analyzer's HAS_ARTIFACT still points at it; a config key only if no other analyzer's marker (:JCanNode, :PyCanNode) claims it. Other analyzers' edges are never removed. An --eager --target-files push reconciles nothing, so stale artifacts wait for the next full --eager push. The graph.cypher snapshot is a full rebuild by design: its wipe deletes every node this application wrote, shared artifacts included, and other analyzers restore their edges on their next push.

The connection options also read the standard Neo4j environment variables — NEO4J_URI, NEO4J_USERNAME, NEO4J_PASSWORD, NEO4J_DATABASE — when the corresponding flag is omitted (an explicit flag wins). Prefer the env var for the password so it doesn't land in shell history or the process list:

export NEO4J_URI=bolt://localhost:7687
export NEO4J_PASSWORD=secret
cants --input ./my-ts-project --emit neo4j     # credentials picked up from the environment

Schema contract

--emit schema writes the machine-readable, version-stamped Neo4j schema (schema.json: node labels, relationships, properties, constraints, and indexes). It needs no project and is bundled in every release (as a wheel asset and a GitHub Release asset), so a consumer can validate producer/consumer compatibility without invoking the binary.

cants --emit schema                 # print to stdout
cants --emit schema --output ./out  # → ./out/schema.json

Development

This project uses Bun as its toolchain.

bun install
bun run start -- --input /path/to/project   # run from source
bun run typecheck                            # type-check
bun test                                     # tests (the Neo4j bolt test is opt-in; see below)
bun run test:container                       # Neo4j bolt tests — needs Docker/Podman (opt-in)
bun run gen:schema                           # regenerate schema.neo4j.json
bun run gen:readme                           # regenerate the cants --help block above

License

Apache 2.0 — see LICENSE.

Polyglot applications: all languages, or none

A --emit neo4j push is destructive. It sweeps everything under can://<namespace>/<app>/ that this analyzer marked, then rewrites what it found. Since the id grammar puts the application outermost, every analyzer over the same <app> shares that prefix — so a push reclaims stale rows belonging to this analyzer and, in the shared namespaces, sweeps rows a sibling wrote.

For most of what is shared that is harmless: the artifact walk is a whole-repo inventory, so an :Artifact a sibling wrote is re-created by this push (with a thinner view of it — roles falls back to unknown and its config keys and dependency edges are gone until that sibling pushes again). @external ghosts are not inventoried that way: they are per-language, so a sibling's ghosts are swept and not restored.

So for an application analysed in more than one language, run every analyzer or none. Running one in isolation leaves the others' derived rows missing until they run again. Running them together is always correct, in any order, because the last push restores everything the batch swept.

Nothing here corrupts a graph: what is lost is derived and regenerates. But a partial run leaves a partial answer, and nothing in the data says so.

Metadata

Release files for codeanalyzer-typescript 1.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for codeanalyzer-typescript 1.7.0
File Actions
codeanalyzer_typescript-1.7.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details for codeanalyzer_typescript-1.7.0-py3-none-win_amd64.whl
codeanalyzer_typescript-1.7.0-py3-none-manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details for codeanalyzer_typescript-1.7.0-py3-none-manylinux2014_x86_64.whl
codeanalyzer_typescript-1.7.0-py3-none-manylinux2014_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details for codeanalyzer_typescript-1.7.0-py3-none-manylinux2014_aarch64.whl
codeanalyzer_typescript-1.7.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details for codeanalyzer_typescript-1.7.0-py3-none-macosx_11_0_arm64.whl
codeanalyzer_typescript-1.7.0-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details for codeanalyzer_typescript-1.7.0-py3-none-macosx_10_12_x86_64.whl

Total release size: 254.7 MB

Release files / codeanalyzer_typescript-1.7.0-py3-none-win_amd64.whl

Download URL codeanalyzer_typescript-1.7.0-py3-none-win_amd64.whl
Size 57.2 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
63f9c714461c13527ffd4b51e4f5d3ec9b78c70cb297c4cd050d1b1f86241435
BLAKE2b-256 checksum
How to use checksums
c7610184e96dd16aba1abd49e6c3e8ebf0545fbbf66337a67bcbd5b2bd9bd3e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / codeanalyzer_typescript-1.7.0-py3-none-manylinux2014_x86_64.whl

Download URL codeanalyzer_typescript-1.7.0-py3-none-manylinux2014_x86_64.whl
Size 54.2 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
b3db65096ede1feaa86e3a4aefbcffb1ac63755cc89bf9a0d17cb08a8e51d5ed
BLAKE2b-256 checksum
How to use checksums
0460544ee697bede23c3a02672644c15e75311ad3e6ea797937f8265f14df4b7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / codeanalyzer_typescript-1.7.0-py3-none-manylinux2014_aarch64.whl

Download URL codeanalyzer_typescript-1.7.0-py3-none-manylinux2014_aarch64.whl
Size 54.1 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
e0a428d0a15e63602eb24e9ccbcdbad9f64022f00b5aabd6e108774bb1e3409d
BLAKE2b-256 checksum
How to use checksums
d0eb2d794862366fd9e2fecec5b0ee2deeeaf3956950f99e13670f44db444ce6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / codeanalyzer_typescript-1.7.0-py3-none-macosx_11_0_arm64.whl

Download URL codeanalyzer_typescript-1.7.0-py3-none-macosx_11_0_arm64.whl
Size 43.4 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
f7c7ea29604fca87ba3d3ef365628b80b331eebfbe3d38433417fdc2c6c1582a
BLAKE2b-256 checksum
How to use checksums
78f8758d9a6eb9839e8f7d8f067ba1e966e2cd21499a3eb39c13e736b1f7cad5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / codeanalyzer_typescript-1.7.0-py3-none-macosx_10_12_x86_64.whl

Download URL codeanalyzer_typescript-1.7.0-py3-none-macosx_10_12_x86_64.whl
Size 45.9 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
17a91643847bb68396c66f30fc8e50fc69d658cc4b0c27eb781130fd62125f1f
BLAKE2b-256 checksum
How to use checksums
dc11427dec5ee6e1a600dd66006ed3534d90181c8359d24f73b0103b05df3287
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Security for codeanalyzer-typescript 1.7.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 5 files in this release have been uploaded with provenance metadata.

Select from 5 files

Attestation for codeanalyzer_typescript-1.7.0-py3-none-win_amd64.whl

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page