codeanalyzer-typescript 1.4.0__py3-none-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codeanalyzer_typescript/__init__.py +76 -0
- codeanalyzer_typescript/__main__.py +34 -0
- codeanalyzer_typescript/_bin/.gitignore +5 -0
- codeanalyzer_typescript/_bin/cants +0 -0
- codeanalyzer_typescript/_bin/schema.json +621 -0
- codeanalyzer_typescript-1.4.0.dist-info/METADATA +389 -0
- codeanalyzer_typescript-1.4.0.dist-info/RECORD +9 -0
- codeanalyzer_typescript-1.4.0.dist-info/WHEEL +5 -0
- codeanalyzer_typescript-1.4.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Prebuilt ``cants`` (codeanalyzer-typescript) backend binary for CLDK.
|
|
2
|
+
|
|
3
|
+
This package carries the platform-specific, self-contained ``cants``
|
|
4
|
+
executable (built from this repo with ``bun build --compile``) and exposes its
|
|
5
|
+
filesystem path. CLDK's Python SDK depends on this package and calls
|
|
6
|
+
:func:`bin_path` to locate the analyzer, exactly as it imports ``codeanalyzer-python``
|
|
7
|
+
for the Python backend.
|
|
8
|
+
|
|
9
|
+
Each published wheel is platform-tagged and contains the single binary for that
|
|
10
|
+
platform; pip resolves the correct wheel at install time.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import stat
|
|
17
|
+
import sys
|
|
18
|
+
from importlib import resources
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
__version__ = "1.4.0"
|
|
22
|
+
|
|
23
|
+
__all__ = ["bin_path", "schema_path", "__version__"]
|
|
24
|
+
|
|
25
|
+
_BINARY_NAME = "cants" + (".exe" if sys.platform == "win32" else "")
|
|
26
|
+
_SCHEMA_NAME = "schema.json"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def bin_path() -> Path:
|
|
30
|
+
"""Return the absolute path to the bundled ``cants`` binary.
|
|
31
|
+
|
|
32
|
+
Raises:
|
|
33
|
+
FileNotFoundError: if the wheel for this platform did not include a binary
|
|
34
|
+
(e.g. an unsupported platform, or a source/dev install with no build run).
|
|
35
|
+
"""
|
|
36
|
+
resource = resources.files("codeanalyzer_typescript") / "_bin" / _BINARY_NAME
|
|
37
|
+
with resources.as_file(resource) as extracted:
|
|
38
|
+
path = Path(extracted)
|
|
39
|
+
|
|
40
|
+
if not path.exists():
|
|
41
|
+
raise FileNotFoundError(
|
|
42
|
+
f"Bundled cants binary not found at {path}. "
|
|
43
|
+
"This usually means there is no prebuilt wheel for your platform; "
|
|
44
|
+
"build the binary with `bun build --compile` and point CLDK at it via "
|
|
45
|
+
"analysis_backend_path or $CODEANALYZER_TS_BIN."
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Wheels may not preserve the executable bit on POSIX; restore it best-effort.
|
|
49
|
+
if os.name == "posix":
|
|
50
|
+
mode = path.stat().st_mode
|
|
51
|
+
path.chmod(mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
|
|
52
|
+
|
|
53
|
+
return path
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def schema_path() -> Path:
|
|
57
|
+
"""Return the absolute path to the bundled Neo4j ``schema.json`` contract.
|
|
58
|
+
|
|
59
|
+
The schema is version-locked to this binary's build (its ``schema_version`` is stamped onto the
|
|
60
|
+
``:Application`` node of every emitted graph), so a consumer can read it to validate
|
|
61
|
+
producer/consumer compatibility without invoking the binary.
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
FileNotFoundError: if the wheel for this platform did not include the schema.
|
|
65
|
+
"""
|
|
66
|
+
resource = resources.files("codeanalyzer_typescript") / "_bin" / _SCHEMA_NAME
|
|
67
|
+
with resources.as_file(resource) as extracted:
|
|
68
|
+
path = Path(extracted)
|
|
69
|
+
|
|
70
|
+
if not path.exists():
|
|
71
|
+
raise FileNotFoundError(
|
|
72
|
+
f"Bundled schema.json not found at {path}. Regenerate it with `cants --emit schema` "
|
|
73
|
+
"or `bun gen:schema`."
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return path
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Console-script entry point: run the bundled ``cants`` binary.
|
|
2
|
+
|
|
3
|
+
``pip install codeanalyzer-typescript`` installs a ``cants`` launcher (see
|
|
4
|
+
``[project.scripts]`` in ``pyproject.toml``) that calls :func:`main`. We locate
|
|
5
|
+
the platform binary via :func:`bin_path` and hand off the process to it, passing
|
|
6
|
+
through every CLI argument and the exit code unchanged.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import subprocess
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
from . import bin_path
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def main() -> "int | None":
|
|
19
|
+
"""Exec the bundled ``cants`` binary with the current argv (minus argv[0])."""
|
|
20
|
+
binary = str(bin_path())
|
|
21
|
+
args = [binary, *sys.argv[1:]]
|
|
22
|
+
|
|
23
|
+
if os.name == "posix":
|
|
24
|
+
# Replace this process with the binary: no extra Python process lingers,
|
|
25
|
+
# and signals/exit codes are handled by cants directly.
|
|
26
|
+
os.execv(binary, args)
|
|
27
|
+
# os.execv never returns on success.
|
|
28
|
+
|
|
29
|
+
# Windows has no execv that behaves like POSIX; spawn and propagate the code.
|
|
30
|
+
return subprocess.call(args)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
sys.exit(main())
|
|
Binary file
|
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": "2.0.0",
|
|
3
|
+
"generator": "codeanalyzer-typescript",
|
|
4
|
+
"marker_labels": [
|
|
5
|
+
"TSCanNode",
|
|
6
|
+
"JSCanNode"
|
|
7
|
+
],
|
|
8
|
+
"node_labels": [
|
|
9
|
+
{
|
|
10
|
+
"label": "TSApplication",
|
|
11
|
+
"mergeLabel": "Application",
|
|
12
|
+
"key": "id",
|
|
13
|
+
"properties": {
|
|
14
|
+
"id": "string",
|
|
15
|
+
"schema_version": "string",
|
|
16
|
+
"language": "string",
|
|
17
|
+
"max_level": "integer",
|
|
18
|
+
"k_limit": "integer",
|
|
19
|
+
"analyzer_name": "string",
|
|
20
|
+
"analyzer_version": "string",
|
|
21
|
+
"entrypoint_frameworks": "string[]",
|
|
22
|
+
"entrypoint_report_json": "string"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"label": "Artifact",
|
|
27
|
+
"mergeLabel": "Artifact",
|
|
28
|
+
"key": "id",
|
|
29
|
+
"properties": {
|
|
30
|
+
"id": "string",
|
|
31
|
+
"kind": "string",
|
|
32
|
+
"path": "string",
|
|
33
|
+
"format": "string",
|
|
34
|
+
"roles": "string[]",
|
|
35
|
+
"size_bytes": "integer",
|
|
36
|
+
"sha256": "string",
|
|
37
|
+
"extraction": "string",
|
|
38
|
+
"source": "string"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"label": "Package",
|
|
43
|
+
"mergeLabel": "Package",
|
|
44
|
+
"key": "id",
|
|
45
|
+
"properties": {
|
|
46
|
+
"id": "string",
|
|
47
|
+
"ecosystem": "string",
|
|
48
|
+
"name": "string"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"label": "TSDecorator",
|
|
53
|
+
"mergeLabel": "TSDecorator",
|
|
54
|
+
"key": "name",
|
|
55
|
+
"properties": {
|
|
56
|
+
"name": "string",
|
|
57
|
+
"qualified_name": "string"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"label": "ConfigKey",
|
|
62
|
+
"mergeLabel": "ConfigKey",
|
|
63
|
+
"key": "id",
|
|
64
|
+
"properties": {
|
|
65
|
+
"id": "string",
|
|
66
|
+
"key": "string",
|
|
67
|
+
"namespace": "string",
|
|
68
|
+
"value": "string",
|
|
69
|
+
"references": "string[]"
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"label": "TSModule",
|
|
74
|
+
"mergeLabel": "CanNode",
|
|
75
|
+
"key": "id",
|
|
76
|
+
"properties": {
|
|
77
|
+
"id": "string",
|
|
78
|
+
"kind": "string",
|
|
79
|
+
"name": "string",
|
|
80
|
+
"is_tsx": "boolean",
|
|
81
|
+
"is_declaration_file": "boolean",
|
|
82
|
+
"content_hash": "string",
|
|
83
|
+
"exports_json": "string",
|
|
84
|
+
"start_line": "integer",
|
|
85
|
+
"end_line": "integer"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"label": "TSClass",
|
|
90
|
+
"mergeLabel": "CanNode",
|
|
91
|
+
"key": "id",
|
|
92
|
+
"properties": {
|
|
93
|
+
"id": "string",
|
|
94
|
+
"kind": "string",
|
|
95
|
+
"signature": "string",
|
|
96
|
+
"name": "string",
|
|
97
|
+
"base_classes": "string[]",
|
|
98
|
+
"implements_types": "string[]",
|
|
99
|
+
"is_abstract": "boolean",
|
|
100
|
+
"is_exported": "boolean",
|
|
101
|
+
"is_ambient": "boolean",
|
|
102
|
+
"code": "string",
|
|
103
|
+
"start_line": "integer",
|
|
104
|
+
"end_line": "integer",
|
|
105
|
+
"is_entrypoint": "boolean",
|
|
106
|
+
"entrypoint_frameworks": "string[]"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"label": "TSInterface",
|
|
111
|
+
"mergeLabel": "CanNode",
|
|
112
|
+
"key": "id",
|
|
113
|
+
"properties": {
|
|
114
|
+
"id": "string",
|
|
115
|
+
"kind": "string",
|
|
116
|
+
"signature": "string",
|
|
117
|
+
"name": "string",
|
|
118
|
+
"base_classes": "string[]",
|
|
119
|
+
"is_exported": "boolean",
|
|
120
|
+
"is_ambient": "boolean",
|
|
121
|
+
"code": "string",
|
|
122
|
+
"start_line": "integer",
|
|
123
|
+
"end_line": "integer"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"label": "TSEnum",
|
|
128
|
+
"mergeLabel": "CanNode",
|
|
129
|
+
"key": "id",
|
|
130
|
+
"properties": {
|
|
131
|
+
"id": "string",
|
|
132
|
+
"kind": "string",
|
|
133
|
+
"signature": "string",
|
|
134
|
+
"name": "string",
|
|
135
|
+
"is_const": "boolean",
|
|
136
|
+
"is_exported": "boolean",
|
|
137
|
+
"is_ambient": "boolean",
|
|
138
|
+
"code": "string",
|
|
139
|
+
"start_line": "integer",
|
|
140
|
+
"end_line": "integer"
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"label": "TSTypeAlias",
|
|
145
|
+
"mergeLabel": "CanNode",
|
|
146
|
+
"key": "id",
|
|
147
|
+
"properties": {
|
|
148
|
+
"id": "string",
|
|
149
|
+
"kind": "string",
|
|
150
|
+
"signature": "string",
|
|
151
|
+
"name": "string",
|
|
152
|
+
"aliased_type": "string",
|
|
153
|
+
"is_exported": "boolean",
|
|
154
|
+
"is_ambient": "boolean",
|
|
155
|
+
"code": "string",
|
|
156
|
+
"start_line": "integer",
|
|
157
|
+
"end_line": "integer"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"label": "TSNamespace",
|
|
162
|
+
"mergeLabel": "CanNode",
|
|
163
|
+
"key": "id",
|
|
164
|
+
"properties": {
|
|
165
|
+
"id": "string",
|
|
166
|
+
"kind": "string",
|
|
167
|
+
"signature": "string",
|
|
168
|
+
"name": "string",
|
|
169
|
+
"is_exported": "boolean",
|
|
170
|
+
"is_ambient": "boolean",
|
|
171
|
+
"code": "string",
|
|
172
|
+
"start_line": "integer",
|
|
173
|
+
"end_line": "integer"
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"label": "TSCallable",
|
|
178
|
+
"mergeLabel": "CanNode",
|
|
179
|
+
"key": "id",
|
|
180
|
+
"properties": {
|
|
181
|
+
"id": "string",
|
|
182
|
+
"kind": "string",
|
|
183
|
+
"signature": "string",
|
|
184
|
+
"name": "string",
|
|
185
|
+
"return_type": "string",
|
|
186
|
+
"cyclomatic_complexity": "integer",
|
|
187
|
+
"accessibility": "string",
|
|
188
|
+
"accessor_kind": "string",
|
|
189
|
+
"is_static": "boolean",
|
|
190
|
+
"is_abstract": "boolean",
|
|
191
|
+
"is_async": "boolean",
|
|
192
|
+
"is_generator": "boolean",
|
|
193
|
+
"is_exported": "boolean",
|
|
194
|
+
"is_ambient": "boolean",
|
|
195
|
+
"is_implicit": "boolean",
|
|
196
|
+
"code": "string",
|
|
197
|
+
"start_line": "integer",
|
|
198
|
+
"end_line": "integer",
|
|
199
|
+
"is_entrypoint": "boolean",
|
|
200
|
+
"entrypoint_frameworks": "string[]",
|
|
201
|
+
"parameters_json": "string"
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"label": "TSField",
|
|
206
|
+
"mergeLabel": "CanNode",
|
|
207
|
+
"key": "id",
|
|
208
|
+
"properties": {
|
|
209
|
+
"id": "string",
|
|
210
|
+
"kind": "string",
|
|
211
|
+
"name": "string",
|
|
212
|
+
"type": "string",
|
|
213
|
+
"start_line": "integer",
|
|
214
|
+
"end_line": "integer"
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"label": "TSBodyNode",
|
|
219
|
+
"mergeLabel": "CanNode",
|
|
220
|
+
"key": "id",
|
|
221
|
+
"properties": {
|
|
222
|
+
"id": "string",
|
|
223
|
+
"kind": "string",
|
|
224
|
+
"of": "string",
|
|
225
|
+
"parent": "string",
|
|
226
|
+
"callee": "string",
|
|
227
|
+
"start_line": "integer",
|
|
228
|
+
"end_line": "integer"
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"label": "TSExternal",
|
|
233
|
+
"mergeLabel": "CanNode",
|
|
234
|
+
"key": "id",
|
|
235
|
+
"properties": {
|
|
236
|
+
"id": "string",
|
|
237
|
+
"kind": "string",
|
|
238
|
+
"name": "string",
|
|
239
|
+
"module": "string"
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"label": "TSAnonymousCallable",
|
|
244
|
+
"mergeLabel": "CanNode",
|
|
245
|
+
"key": "id",
|
|
246
|
+
"properties": {
|
|
247
|
+
"id": "string",
|
|
248
|
+
"kind": "string",
|
|
249
|
+
"signature": "string",
|
|
250
|
+
"name": "string",
|
|
251
|
+
"return_type": "string",
|
|
252
|
+
"cyclomatic_complexity": "integer",
|
|
253
|
+
"accessibility": "string",
|
|
254
|
+
"accessor_kind": "string",
|
|
255
|
+
"is_static": "boolean",
|
|
256
|
+
"is_abstract": "boolean",
|
|
257
|
+
"is_async": "boolean",
|
|
258
|
+
"is_generator": "boolean",
|
|
259
|
+
"is_exported": "boolean",
|
|
260
|
+
"is_ambient": "boolean",
|
|
261
|
+
"is_implicit": "boolean",
|
|
262
|
+
"path": "string",
|
|
263
|
+
"start_column": "integer",
|
|
264
|
+
"start_line": "integer",
|
|
265
|
+
"end_line": "integer"
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
],
|
|
269
|
+
"relationship_types": [
|
|
270
|
+
{
|
|
271
|
+
"type": "TS_HAS_MODULE",
|
|
272
|
+
"from": [
|
|
273
|
+
"TSApplication"
|
|
274
|
+
],
|
|
275
|
+
"to": [
|
|
276
|
+
"TSModule"
|
|
277
|
+
],
|
|
278
|
+
"properties": {}
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"type": "HAS_ARTIFACT",
|
|
282
|
+
"from": [
|
|
283
|
+
"TSApplication"
|
|
284
|
+
],
|
|
285
|
+
"to": [
|
|
286
|
+
"Artifact"
|
|
287
|
+
],
|
|
288
|
+
"properties": {}
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"type": "DECLARES_DEPENDENCY",
|
|
292
|
+
"from": [
|
|
293
|
+
"Artifact"
|
|
294
|
+
],
|
|
295
|
+
"to": [
|
|
296
|
+
"Package"
|
|
297
|
+
],
|
|
298
|
+
"properties": {
|
|
299
|
+
"spec": "string",
|
|
300
|
+
"kind": "string",
|
|
301
|
+
"direct": "boolean",
|
|
302
|
+
"extras": "string[]",
|
|
303
|
+
"prov": "string[]"
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
"type": "LOCKS",
|
|
308
|
+
"from": [
|
|
309
|
+
"Artifact"
|
|
310
|
+
],
|
|
311
|
+
"to": [
|
|
312
|
+
"Package"
|
|
313
|
+
],
|
|
314
|
+
"properties": {
|
|
315
|
+
"version": "string"
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
"type": "TS_PROVIDES",
|
|
320
|
+
"from": [
|
|
321
|
+
"Package"
|
|
322
|
+
],
|
|
323
|
+
"to": [
|
|
324
|
+
"TSExternal"
|
|
325
|
+
],
|
|
326
|
+
"properties": {}
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
"type": "TS_UNRESOLVED_IMPORT",
|
|
330
|
+
"from": [
|
|
331
|
+
"TSApplication"
|
|
332
|
+
],
|
|
333
|
+
"to": [
|
|
334
|
+
"TSExternal"
|
|
335
|
+
],
|
|
336
|
+
"properties": {
|
|
337
|
+
"prov": "string[]"
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"type": "DEFINES_CONFIG",
|
|
342
|
+
"from": [
|
|
343
|
+
"Artifact"
|
|
344
|
+
],
|
|
345
|
+
"to": [
|
|
346
|
+
"ConfigKey"
|
|
347
|
+
],
|
|
348
|
+
"properties": {}
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"type": "TS_USES_CONFIG",
|
|
352
|
+
"from": [
|
|
353
|
+
"TSBodyNode"
|
|
354
|
+
],
|
|
355
|
+
"to": [
|
|
356
|
+
"ConfigKey"
|
|
357
|
+
],
|
|
358
|
+
"properties": {
|
|
359
|
+
"prov": "string[]"
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
"type": "TS_READS_CONFIG_UNRESOLVED",
|
|
364
|
+
"from": [
|
|
365
|
+
"TSApplication"
|
|
366
|
+
],
|
|
367
|
+
"to": [
|
|
368
|
+
"TSExternal",
|
|
369
|
+
"TSCallable"
|
|
370
|
+
],
|
|
371
|
+
"properties": {
|
|
372
|
+
"key": "string",
|
|
373
|
+
"reason": "string",
|
|
374
|
+
"prov": "string[]",
|
|
375
|
+
"_k": "string"
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
"type": "TS_IMPORTS",
|
|
380
|
+
"from": [
|
|
381
|
+
"TSModule"
|
|
382
|
+
],
|
|
383
|
+
"to": [
|
|
384
|
+
"TSModule",
|
|
385
|
+
"TSExternal"
|
|
386
|
+
],
|
|
387
|
+
"properties": {
|
|
388
|
+
"spellings": "string[]",
|
|
389
|
+
"imported_names": "string[]",
|
|
390
|
+
"aliases": "string[]",
|
|
391
|
+
"type_only_names": "string[]"
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
"type": "TS_RE_EXPORTS",
|
|
396
|
+
"from": [
|
|
397
|
+
"TSModule"
|
|
398
|
+
],
|
|
399
|
+
"to": [
|
|
400
|
+
"TSModule",
|
|
401
|
+
"TSExternal"
|
|
402
|
+
],
|
|
403
|
+
"properties": {
|
|
404
|
+
"spellings": "string[]",
|
|
405
|
+
"exported_names": "string[]",
|
|
406
|
+
"aliases": "string[]",
|
|
407
|
+
"type_only_names": "string[]"
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"type": "TS_DECLARES",
|
|
412
|
+
"from": [
|
|
413
|
+
"TSModule",
|
|
414
|
+
"TSNamespace",
|
|
415
|
+
"TSCallable"
|
|
416
|
+
],
|
|
417
|
+
"to": [
|
|
418
|
+
"TSClass",
|
|
419
|
+
"TSInterface",
|
|
420
|
+
"TSEnum",
|
|
421
|
+
"TSTypeAlias",
|
|
422
|
+
"TSNamespace",
|
|
423
|
+
"TSCallable"
|
|
424
|
+
],
|
|
425
|
+
"properties": {}
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"type": "TS_HAS_METHOD",
|
|
429
|
+
"from": [
|
|
430
|
+
"TSClass",
|
|
431
|
+
"TSInterface"
|
|
432
|
+
],
|
|
433
|
+
"to": [
|
|
434
|
+
"TSCallable"
|
|
435
|
+
],
|
|
436
|
+
"properties": {}
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
"type": "TS_HAS_FIELD",
|
|
440
|
+
"from": [
|
|
441
|
+
"TSModule",
|
|
442
|
+
"TSClass",
|
|
443
|
+
"TSInterface",
|
|
444
|
+
"TSEnum",
|
|
445
|
+
"TSNamespace"
|
|
446
|
+
],
|
|
447
|
+
"to": [
|
|
448
|
+
"TSField"
|
|
449
|
+
],
|
|
450
|
+
"properties": {}
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
"type": "TS_DECORATED_BY",
|
|
454
|
+
"from": [
|
|
455
|
+
"TSClass",
|
|
456
|
+
"TSInterface",
|
|
457
|
+
"TSEnum",
|
|
458
|
+
"TSNamespace",
|
|
459
|
+
"TSCallable",
|
|
460
|
+
"TSField"
|
|
461
|
+
],
|
|
462
|
+
"to": [
|
|
463
|
+
"TSDecorator"
|
|
464
|
+
],
|
|
465
|
+
"properties": {
|
|
466
|
+
"positional_arguments": "string[]",
|
|
467
|
+
"keyword_arguments_json": "string"
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"type": "TS_HAS_BODY_NODE",
|
|
472
|
+
"from": [
|
|
473
|
+
"TSCallable",
|
|
474
|
+
"TSAnonymousCallable"
|
|
475
|
+
],
|
|
476
|
+
"to": [
|
|
477
|
+
"TSBodyNode"
|
|
478
|
+
],
|
|
479
|
+
"properties": {}
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
"type": "TS_RESOLVES_TO",
|
|
483
|
+
"from": [
|
|
484
|
+
"TSBodyNode"
|
|
485
|
+
],
|
|
486
|
+
"to": [
|
|
487
|
+
"TSCallable",
|
|
488
|
+
"TSExternal",
|
|
489
|
+
"TSAnonymousCallable"
|
|
490
|
+
],
|
|
491
|
+
"properties": {}
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
"type": "TS_CALLS",
|
|
495
|
+
"from": [
|
|
496
|
+
"TSCallable",
|
|
497
|
+
"TSAnonymousCallable"
|
|
498
|
+
],
|
|
499
|
+
"to": [
|
|
500
|
+
"TSCallable",
|
|
501
|
+
"TSExternal",
|
|
502
|
+
"TSAnonymousCallable"
|
|
503
|
+
],
|
|
504
|
+
"properties": {
|
|
505
|
+
"weight": "integer",
|
|
506
|
+
"prov": "string[]"
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
"type": "TS_CFG_NEXT",
|
|
511
|
+
"from": [
|
|
512
|
+
"TSBodyNode"
|
|
513
|
+
],
|
|
514
|
+
"to": [
|
|
515
|
+
"TSBodyNode"
|
|
516
|
+
],
|
|
517
|
+
"properties": {
|
|
518
|
+
"kind": "string",
|
|
519
|
+
"_k": "string"
|
|
520
|
+
}
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
"type": "TS_CDG",
|
|
524
|
+
"from": [
|
|
525
|
+
"TSBodyNode"
|
|
526
|
+
],
|
|
527
|
+
"to": [
|
|
528
|
+
"TSBodyNode"
|
|
529
|
+
],
|
|
530
|
+
"properties": {}
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
"type": "TS_DDG",
|
|
534
|
+
"from": [
|
|
535
|
+
"TSBodyNode"
|
|
536
|
+
],
|
|
537
|
+
"to": [
|
|
538
|
+
"TSBodyNode"
|
|
539
|
+
],
|
|
540
|
+
"properties": {
|
|
541
|
+
"var": "string",
|
|
542
|
+
"prov": "string[]",
|
|
543
|
+
"_k": "string"
|
|
544
|
+
}
|
|
545
|
+
},
|
|
546
|
+
{
|
|
547
|
+
"type": "TS_SUMMARY",
|
|
548
|
+
"from": [
|
|
549
|
+
"TSBodyNode"
|
|
550
|
+
],
|
|
551
|
+
"to": [
|
|
552
|
+
"TSBodyNode"
|
|
553
|
+
],
|
|
554
|
+
"properties": {
|
|
555
|
+
"var": "string"
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
"type": "TS_PARAM_IN",
|
|
560
|
+
"from": [
|
|
561
|
+
"TSBodyNode"
|
|
562
|
+
],
|
|
563
|
+
"to": [
|
|
564
|
+
"TSBodyNode"
|
|
565
|
+
],
|
|
566
|
+
"properties": {
|
|
567
|
+
"var": "string"
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
"type": "TS_PARAM_OUT",
|
|
572
|
+
"from": [
|
|
573
|
+
"TSBodyNode"
|
|
574
|
+
],
|
|
575
|
+
"to": [
|
|
576
|
+
"TSBodyNode"
|
|
577
|
+
],
|
|
578
|
+
"properties": {
|
|
579
|
+
"var": "string"
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
"type": "TS_EXTENDS",
|
|
584
|
+
"from": [
|
|
585
|
+
"TSClass",
|
|
586
|
+
"TSInterface"
|
|
587
|
+
],
|
|
588
|
+
"to": [
|
|
589
|
+
"TSClass",
|
|
590
|
+
"TSInterface"
|
|
591
|
+
],
|
|
592
|
+
"properties": {}
|
|
593
|
+
},
|
|
594
|
+
{
|
|
595
|
+
"type": "TS_IMPLEMENTS",
|
|
596
|
+
"from": [
|
|
597
|
+
"TSClass"
|
|
598
|
+
],
|
|
599
|
+
"to": [
|
|
600
|
+
"TSInterface",
|
|
601
|
+
"TSClass"
|
|
602
|
+
],
|
|
603
|
+
"properties": {}
|
|
604
|
+
}
|
|
605
|
+
],
|
|
606
|
+
"constraints": [
|
|
607
|
+
"CREATE CONSTRAINT application_id IF NOT EXISTS FOR (x:Application) REQUIRE x.id IS UNIQUE",
|
|
608
|
+
"CREATE CONSTRAINT artifact_id IF NOT EXISTS FOR (x:Artifact) REQUIRE x.id IS UNIQUE",
|
|
609
|
+
"CREATE CONSTRAINT package_id IF NOT EXISTS FOR (x:Package) REQUIRE x.id IS UNIQUE",
|
|
610
|
+
"CREATE CONSTRAINT tsdecorator_name IF NOT EXISTS FOR (x:TSDecorator) REQUIRE x.name IS UNIQUE",
|
|
611
|
+
"CREATE CONSTRAINT configkey_id IF NOT EXISTS FOR (x:ConfigKey) REQUIRE x.id IS UNIQUE",
|
|
612
|
+
"CREATE CONSTRAINT cannode_id IF NOT EXISTS FOR (x:CanNode) REQUIRE x.id IS UNIQUE"
|
|
613
|
+
],
|
|
614
|
+
"indexes": [
|
|
615
|
+
"CREATE INDEX callable_name IF NOT EXISTS FOR (c:TSCallable) ON (c.name)",
|
|
616
|
+
"CREATE FULLTEXT INDEX ts_code_fts IF NOT EXISTS FOR (c:TSCallable) ON EACH [c.code]",
|
|
617
|
+
"CREATE INDEX cannode_kind IF NOT EXISTS FOR (n:CanNode) ON (n.kind)",
|
|
618
|
+
"CREATE INDEX tscannode_id IF NOT EXISTS FOR (n:TSCanNode) ON (n.id)",
|
|
619
|
+
"CREATE INDEX jscannode_id IF NOT EXISTS FOR (n:JSCanNode) ON (n.id)"
|
|
620
|
+
]
|
|
621
|
+
}
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: codeanalyzer-typescript
|
|
3
|
+
Version: 1.4.0
|
|
4
|
+
Summary: Prebuilt codeanalyzer-typescript backend binary for CLDK (codellm-devkit).
|
|
5
|
+
Project-URL: Homepage, https://codellm-devkit.info
|
|
6
|
+
Project-URL: Repository, https://github.com/codellm-devkit/codeanalyzer-ts
|
|
7
|
+
Author-email: Rahul Krishna <i.m.ralk@gmail.com>
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Keywords: cldk,code analysis,codellm-devkit,typescript
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Requires-Python: >=3.8
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
<div align="center">
|
|
18
|
+
|
|
19
|
+
<img src="https://github.com/codellm-devkit/codeanalyzer-python/blob/main/docs/assets/logo.png?raw=true" alt="CodeLLM-DevKit" />
|
|
20
|
+
|
|
21
|
+
# codeanalyzer-typescript (`cants`)
|
|
22
|
+
|
|
23
|
+
**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.**
|
|
24
|
+
|
|
25
|
+
[](https://pypi.org/project/codeanalyzer-typescript/)
|
|
26
|
+
[](https://pypi.org/project/codeanalyzer-typescript/)
|
|
27
|
+
[](https://github.com/codellm-devkit/codeanalyzer-typescript/actions/workflows/release.yml)
|
|
28
|
+
[](./LICENSE)
|
|
29
|
+
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
`cants` is a static analyzer for TypeScript/JavaScript built on the TypeScript compiler (via
|
|
35
|
+
[ts-morph](https://ts-morph.com/)). It produces the canonical CodeLLM-DevKit (CLDK) **schema v2**
|
|
36
|
+
— one additive Code Property Graph, built up level by level (symbol table → call graph →
|
|
37
|
+
intraprocedural dataflow → interprocedural SDG) — as `analysis.json` and can project that same
|
|
38
|
+
structure into a **Neo4j property graph**. It is the TypeScript backend behind
|
|
39
|
+
[CLDK](https://github.com/codellm-devkit/python-sdk), mirroring its
|
|
40
|
+
[Python](https://github.com/codellm-devkit/codeanalyzer-python) and
|
|
41
|
+
[Java](https://github.com/codellm-devkit/codeanalyzer-java) siblings.
|
|
42
|
+
|
|
43
|
+
The call graph is the TypeScript compiler's resolver plus a **defuse linker** — a deterministic,
|
|
44
|
+
per-callable pass that backfills the edges the resolver misses (alias chains, decorator
|
|
45
|
+
invocations, callbacks handed to library calls, parameter-flow calls) with no whole-program
|
|
46
|
+
fixpoint. Edges keep a `provenance` tag (`tsc` / `defuse` / `import`), so you can tell the layers
|
|
47
|
+
apart, and the output is byte-identical across runs.
|
|
48
|
+
|
|
49
|
+
## Table of Contents
|
|
50
|
+
|
|
51
|
+
- [Features](#features)
|
|
52
|
+
- [Installation](#installation)
|
|
53
|
+
- [Prerequisites](#prerequisites)
|
|
54
|
+
- [Install via shell script](#install-via-shell-script)
|
|
55
|
+
- [Install via Homebrew](#install-via-homebrew)
|
|
56
|
+
- [Install via pip (PyPI)](#install-via-pip-pypi)
|
|
57
|
+
- [Build from source](#build-from-source)
|
|
58
|
+
- [Usage](#usage)
|
|
59
|
+
- [Options](#options)
|
|
60
|
+
- [Examples](#examples)
|
|
61
|
+
- [Output targets](#output-targets)
|
|
62
|
+
- [`analysis.json` (default)](#analysisjson-default)
|
|
63
|
+
- [Neo4j graph](#neo4j-graph)
|
|
64
|
+
- [Schema contract](#schema-contract)
|
|
65
|
+
- [Development](#development)
|
|
66
|
+
- [License](#license)
|
|
67
|
+
|
|
68
|
+
## Features
|
|
69
|
+
|
|
70
|
+
- **Symbol table** — modules, classes, interfaces, enums, type aliases, namespaces, functions,
|
|
71
|
+
methods, variables, decorators, and JSDoc, with precise source spans.
|
|
72
|
+
- **Call graph** — the TypeScript compiler's resolver plus Rapid Type Analysis (RTA), with
|
|
73
|
+
**phantom (external) nodes** for calls into imported libraries and Node builtins.
|
|
74
|
+
- **Defuse linker** — a deterministic per-callable pass over the resolver's leftovers: alias
|
|
75
|
+
chains, decorator invocations, library-callback edges, and bounded interprocedural votes —
|
|
76
|
+
validated as a strict superset of Joern's real call pairs on the reference corpus.
|
|
77
|
+
- **Repository-artifact layer** — every non-code file (manifests, lockfiles, CI, containers, env)
|
|
78
|
+
inventoried with flat, evidence-tagged dependencies (direct and transitive) and a `ConfigKey`
|
|
79
|
+
family joined to the code that reads it via a level-graded `config_use` edge; see
|
|
80
|
+
`docs/skills/analyzing-cants-graphs/`.
|
|
81
|
+
- **Neo4j output** — project the analysis into a labeled property graph: a self-contained
|
|
82
|
+
`graph.cypher` snapshot, or an **incremental** push to a live database over Bolt.
|
|
83
|
+
- **Versioned schema** — a machine-readable, version-stamped Neo4j schema contract
|
|
84
|
+
(`--emit schema`), bundled in every release and enforced by a conformance test.
|
|
85
|
+
- **Self-contained binary** — no Bun or Node required at runtime; install via `pip`, Homebrew, or a
|
|
86
|
+
one-line shell script.
|
|
87
|
+
- **Incremental** — content-hash caching so re-analyzing (and re-loading the graph) only touches
|
|
88
|
+
what changed.
|
|
89
|
+
|
|
90
|
+
## Installation
|
|
91
|
+
|
|
92
|
+
### Prerequisites
|
|
93
|
+
|
|
94
|
+
Running a prebuilt `cants` binary requires **nothing** — it is fully self-contained. To *analyze* a
|
|
95
|
+
project, that project should be a normal Node/TypeScript project (so the compiler can resolve types
|
|
96
|
+
and imports). Building `cants` from source requires [Bun](https://bun.sh/) 1.0+.
|
|
97
|
+
|
|
98
|
+
### Install via shell script
|
|
99
|
+
|
|
100
|
+
Download and install the prebuilt binary for your platform from the latest release:
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/codellm-devkit/codeanalyzer-typescript/releases/latest/download/cants-installer.sh | sh
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The installer drops `cants` into `~/.local/bin` (override with `CANTS_INSTALL_DIR`) and can pin a
|
|
107
|
+
version with `CANTS_VERSION=vX.Y.Z`. Supports macOS (arm64/x86_64) and Linux (x86_64/aarch64).
|
|
108
|
+
|
|
109
|
+
### Install via Homebrew
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
brew install codellm-devkit/homebrew-tap/codeanalyzer-typescript
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Install via pip (PyPI)
|
|
116
|
+
|
|
117
|
+
The wheel bundles the prebuilt, self-contained binary for your platform (no Bun or Node required):
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
pip install codeanalyzer-typescript
|
|
121
|
+
cants --help
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
This is also the package CLDK's Python SDK depends on to locate the analyzer backend; it exposes
|
|
125
|
+
`codeanalyzer_typescript.bin_path()` and `schema_path()`.
|
|
126
|
+
|
|
127
|
+
### Build from source
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
# Install Bun, then:
|
|
131
|
+
git clone https://github.com/codellm-devkit/codeanalyzer-typescript
|
|
132
|
+
cd codeanalyzer-typescript
|
|
133
|
+
bun install
|
|
134
|
+
bun run build # → dist/cants (standalone native binary)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
You can also run the analyzer directly from source without compiling:
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
bun run start -- --input /path/to/typescript/project
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Usage
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
cants --input /path/to/typescript/project
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
With no `--output`, the analysis is printed to stdout as compact JSON; with `--output <dir>` it is
|
|
150
|
+
written to `analysis.json` (or `graph.cypher` for `--emit neo4j`) in that directory.
|
|
151
|
+
|
|
152
|
+
### Options
|
|
153
|
+
|
|
154
|
+
<!-- BEGIN cants-help -->
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
Usage: cants [options]
|
|
158
|
+
|
|
159
|
+
CLDK TypeScript analyzer — emits the canonical schema-v2 CPG (symbol table →
|
|
160
|
+
call graph → dataflow → SDG) as analysis.json, or a Neo4j graph.
|
|
161
|
+
|
|
162
|
+
Options:
|
|
163
|
+
-i, --input <path> project root to analyze (not required for
|
|
164
|
+
--emit schema)
|
|
165
|
+
-o, --output <dir> output directory (omit ⇒ compact output to
|
|
166
|
+
stdout)
|
|
167
|
+
--emit <target> output target: json (analysis.json, default) |
|
|
168
|
+
neo4j (graph.cypher or live push) | schema (the
|
|
169
|
+
Neo4j schema.json contract) (default: "json")
|
|
170
|
+
--app-name <name> logical application name for the graph
|
|
171
|
+
:Application anchor (default: input dir name)
|
|
172
|
+
--neo4j-uri <uri> push the graph to a live Neo4j over Bolt
|
|
173
|
+
(incremental); omit to write graph.cypher (env:
|
|
174
|
+
NEO4J_URI)
|
|
175
|
+
--neo4j-user <user> Neo4j username (default: "neo4j", env:
|
|
176
|
+
NEO4J_USERNAME)
|
|
177
|
+
--neo4j-password <password> Neo4j password (prefer the env var; a flag is
|
|
178
|
+
visible in shell history / process list)
|
|
179
|
+
(default: "neo4j", env: NEO4J_PASSWORD)
|
|
180
|
+
--neo4j-database <db> Neo4j database name (env: NEO4J_DATABASE)
|
|
181
|
+
-a, --analysis-level <n> analysis depth: 1 = symbol table (default); 2 =
|
|
182
|
+
+ resolver call graph; 3 = + intraprocedural
|
|
183
|
+
dataflow (cfg/cdg/ddg); 4 = + interprocedural
|
|
184
|
+
SDG (param_in/param_out/summary) (default: "1")
|
|
185
|
+
--graphs <list> dataflow sections to emit, comma-separated: cfg
|
|
186
|
+
| dfg | pdg (require -a 3) | sdg (requires -a
|
|
187
|
+
4); default: all rungs at or below the level
|
|
188
|
+
--graph-field-depth <k> access-path depth bound (k-limit) for level-3
|
|
189
|
+
dataflow (default: "3")
|
|
190
|
+
-j, --jobs <n> worker parallelism for level-3 graphs (default:
|
|
191
|
+
sequential; opt in with N ≥ 2 on large projects
|
|
192
|
+
— each worker loads its own copy of the
|
|
193
|
+
program)
|
|
194
|
+
-t, --target-files <paths...> restrict analysis to specific files
|
|
195
|
+
(incremental)
|
|
196
|
+
--skip-tests skip test trees (default)
|
|
197
|
+
--include-tests include test trees
|
|
198
|
+
--eager force a clean rebuild instead of reusing the
|
|
199
|
+
cache
|
|
200
|
+
--lazy reuse the cache (default)
|
|
201
|
+
--no-build skip dependency materialization (use a prepared
|
|
202
|
+
node_modules)
|
|
203
|
+
--no-phantoms disable phantom (external) nodes for
|
|
204
|
+
imported/required library calls
|
|
205
|
+
--resolve-installed probe node_modules metadata for import→package
|
|
206
|
+
binding (default: repo files only)
|
|
207
|
+
--no-artifact-text keep the artifact inventory but drop captured
|
|
208
|
+
raw text
|
|
209
|
+
--entrypoint-rules <yaml...> extra entrypoint rules file(s), merged with the
|
|
210
|
+
shipped set; repeatable
|
|
211
|
+
--program <tsconfig...> restrict the run to these programs, named by
|
|
212
|
+
scope dir relative to --input ('<root>' for the
|
|
213
|
+
root program); repeatable
|
|
214
|
+
--list-programs list the discovered programs, one per line, and
|
|
215
|
+
exit
|
|
216
|
+
--emit-ir persist this shard's graph IR for a later
|
|
217
|
+
cross-shard stitch
|
|
218
|
+
--no-repo-sections skip artifacts/dependencies/unresolved_imports
|
|
219
|
+
(repo-scoped; compute them once per repository,
|
|
220
|
+
not once per shard)
|
|
221
|
+
-c, --cache-dir <dir> cache/intermediate directory
|
|
222
|
+
-v, --verbose increase verbosity (repeatable)
|
|
223
|
+
-h, --help display help for command
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
<!-- END cants-help -->
|
|
227
|
+
|
|
228
|
+
### Examples
|
|
229
|
+
|
|
230
|
+
1. **Basic analysis to stdout, or to a file:**
|
|
231
|
+
```sh
|
|
232
|
+
cants --input ./my-ts-project # compact JSON on stdout
|
|
233
|
+
cants --input ./my-ts-project --output ./out # → ./out/analysis.json
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
2. **Emit a Neo4j snapshot, or push to a live database:**
|
|
237
|
+
```sh
|
|
238
|
+
cants --input ./my-ts-project --emit neo4j --output ./out # → ./out/graph.cypher
|
|
239
|
+
cants --input ./my-ts-project --emit neo4j \
|
|
240
|
+
--neo4j-uri bolt://localhost:7687 --neo4j-user neo4j --neo4j-password secret
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
3. **Incremental analysis of specific files:**
|
|
244
|
+
```sh
|
|
245
|
+
cants --input ./my-ts-project --target-files src/a.ts src/b.ts
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
4. **Force a clean rebuild with a custom cache directory:**
|
|
249
|
+
```sh
|
|
250
|
+
cants --input ./my-ts-project --eager --cache-dir /path/to/custom-cache
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
5. **Program graphs (level 3): CFG/PDG/SDG in `analysis.json`:**
|
|
254
|
+
```sh
|
|
255
|
+
cants --input ./my-ts-project -a 3 # full program_graphs section
|
|
256
|
+
cants --input ./my-ts-project -a 3 --graphs cfg,pdg # scope the emitted graphs
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Output targets
|
|
260
|
+
|
|
261
|
+
`cants` builds one analysis in memory and can emit it three ways (`--emit`):
|
|
262
|
+
|
|
263
|
+
### `analysis.json` (default)
|
|
264
|
+
|
|
265
|
+
The **canonical schema v2** — one additive Code Property Graph: a containment tree of nodes
|
|
266
|
+
(`id` / `kind` / `span` / children) with typed edge overlays. Analysis **levels** populate it more
|
|
267
|
+
deeply; each level only ever *adds*.
|
|
268
|
+
|
|
269
|
+
```jsonc
|
|
270
|
+
{
|
|
271
|
+
"schema_version": "2.0.0", "language": "typescript", "max_level": 4, "k_limit": 3,
|
|
272
|
+
"application": {
|
|
273
|
+
"id": "can://typescript/<app>", "kind": "application",
|
|
274
|
+
"symbol_table": { // L1: the tree, keyed by file path
|
|
275
|
+
"<file>": { "kind": "module", "source": "…",
|
|
276
|
+
"types": { /* class | interface | enum | type_alias | namespace nodes */ },
|
|
277
|
+
"functions": { /* callable nodes: { id, kind, span, body{}, cfg[], cdg[], ddg[], summary[] } */ },
|
|
278
|
+
"fields": { /* module-level bindings */ } } },
|
|
279
|
+
"call_graph": [ /* L2: { src, dst, prov, weight } — callable → callable, can:// ids */ ],
|
|
280
|
+
"param_in": [ /* L4: actual_in → formal_in, fully-qualified can://…@local ids */ ],
|
|
281
|
+
"param_out": [ /* L4: formal_out → actual_out */ ]
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Each callable's `body{}` is keyed by local id (`line:col`, or `@entry`/`@formal_in:N`/… for
|
|
287
|
+
synthetic vertices); intra-callable edge lists (`cfg`/`cdg`/`ddg`/`summary`) use those bare local
|
|
288
|
+
ids, cross-callable lists use fully-qualified `can://…@local` ids. A single signature canonicalizer
|
|
289
|
+
underlies every `can://` id, so call edges, dataflow edges, and tree nodes all join. The full model
|
|
290
|
+
is `.claude/SCHEMA_DECISIONS.md` (§ "Schema v2 migration") and the CLDK `canonical-schema.md`.
|
|
291
|
+
|
|
292
|
+
### Dataflow (`-a 3` intraprocedural, `-a 4` interprocedural)
|
|
293
|
+
|
|
294
|
+
Native dependence graphs, built in-process from the same ts-morph AST (no external engine), grown
|
|
295
|
+
**into the tree** (not a separate section):
|
|
296
|
+
|
|
297
|
+
- **`-a 3`** completes each callable's `body{}` with statement nodes and hangs the intra-callable
|
|
298
|
+
edge lists `cfg` (exceptional control flow), `cdg` (control dependence), and `ddg` (data
|
|
299
|
+
dependence via reaching-definitions, `prov:["reaching-defs"]`) on the callable.
|
|
300
|
+
- **`-a 4`** adds the synthetic `@formal_in:N` / `@formal_out` / `<L>/actual_in:N` / `<L>/actual_out`
|
|
301
|
+
vertices, the intra-caller `summary` edges, and the application-scope `param_in` / `param_out`
|
|
302
|
+
lists — the whole-program System Dependence Graph.
|
|
303
|
+
|
|
304
|
+
`-a 3` implies `-a 2`; `-a 4` implies `-a 3`. `--graphs cfg,dfg,pdg,sdg` scopes which rungs emit
|
|
305
|
+
(`cfg`/`dfg`/`pdg` require `-a 3`, `sdg` requires `-a 4`). `L1 ⊆ L2 ⊆ L3 ⊆ L4` is a monotonicity
|
|
306
|
+
gate. Every node is addressed by its `can://…@local` id, so dataflow edges, call edges, and tree
|
|
307
|
+
nodes all join.
|
|
308
|
+
|
|
309
|
+
**Substrate (locked in [issue #2](https://github.com/codellm-devkit/codeanalyzer-typescript/issues/2)):**
|
|
310
|
+
the CFG and reaching-definitions are hand-built from the ts-morph AST; the call-graph oracle is
|
|
311
|
+
the provenance-merged tsc + defuse graph; aliasing is a flow-insensitive copy-alias MVP
|
|
312
|
+
(points-to-backed propagation is a staged upgrade). Function summaries are composed
|
|
313
|
+
bottom-up over the SCC condensation of the call graph, with k-limited access paths; module
|
|
314
|
+
globals ride the SDG as extra parameters. The analysis is deliberately sound-leaning and
|
|
315
|
+
over-approximate; known unsoundness (dynamic `eval`, reflection/monkey-patching, npm-internal
|
|
316
|
+
effects) is recorded in `.claude/SCHEMA_DECISIONS.md`. The analyzer is a **pure graph provider**:
|
|
317
|
+
it emits the dependence-graph substrate (CFG/PDG/SDG + `summary` edges) and stops — backward
|
|
318
|
+
slicing and taint are reachability *queries* over the SDG that live in the frontend SDK, not here.
|
|
319
|
+
|
|
320
|
+
**Parallelism (`-j/--jobs`).** The pipeline implements the level-3 parallel execution model:
|
|
321
|
+
stage-1–4 extraction fans out per callable over a Bun worker pool (partitioned by file) and is
|
|
322
|
+
posted *before* the call-graph solve so the two overlap; summary composition runs as a
|
|
323
|
+
Kahn-style ready-queue wavefront over the SCC condensation DAG (the SCC is the atomic unit).
|
|
324
|
+
`--jobs N` output is **byte-identical** to `--jobs 1` (node ids are span-ordered, all edge lists
|
|
325
|
+
are collect-then-sorted, and the SCC fixpoint is a pure function of its inputs) — enforced by a
|
|
326
|
+
differential test. It is off by default and worth opting into only on large codebases: ts-morph
|
|
327
|
+
ASTs cannot cross the worker boundary, so each extraction worker loads its own copy of the
|
|
328
|
+
program, which dominates the parallelizable graph math on small/mid repos (self-analysis runs
|
|
329
|
+
2.5× slower at `-j 14`). Worker failure at any stage degrades to the sequential path with a
|
|
330
|
+
warning — never to wrong or missing output.
|
|
331
|
+
|
|
332
|
+
Levels 1/2 are unaffected: nothing in level 3 runs unless `-a 3` is requested.
|
|
333
|
+
|
|
334
|
+
### Neo4j graph
|
|
335
|
+
|
|
336
|
+
`--emit neo4j` projects the **same v2 tree** into a labeled property graph: every node keyed by its
|
|
337
|
+
`can://` id under a shared `:CanNode` merge label (+ a `TS`-prefixed specific kind label, e.g.
|
|
338
|
+
`:TSModule`, `:TSCallable`), containment as `TS_HAS_MODULE`/`TS_DECLARES`/`TS_HAS_METHOD`/
|
|
339
|
+
`TS_HAS_FIELD`/`TS_HAS_BODY_NODE` edges, and the overlays (`TS_CALLS`, `TS_CFG_NEXT`, `TS_CDG`,
|
|
340
|
+
`TS_DDG`, `TS_SUMMARY`, `TS_PARAM_IN`, `TS_PARAM_OUT`) as typed relationships. The graph is
|
|
341
|
+
**always full-depth** — analysis levels gate the JSON path only, so combining `-a`/`--graphs` with
|
|
342
|
+
`--emit neo4j` is an error:
|
|
343
|
+
|
|
344
|
+
- **Without `--neo4j-uri`** — writes a self-contained `graph.cypher` (constraints + indexes, a
|
|
345
|
+
scoped wipe, then batched `MERGE`s). Load it with `cypher-shell < graph.cypher`.
|
|
346
|
+
- **With `--neo4j-uri`** — pushes to a live Neo4j over Bolt **incrementally**: only modules whose
|
|
347
|
+
content hash changed are rewritten, and on a full run modules whose source file vanished are
|
|
348
|
+
pruned. Every graph carries a `schema_version` on its `:Application` node.
|
|
349
|
+
|
|
350
|
+
The connection options also read the standard Neo4j environment variables — `NEO4J_URI`,
|
|
351
|
+
`NEO4J_USERNAME`, `NEO4J_PASSWORD`, `NEO4J_DATABASE` — when the corresponding flag is omitted (an
|
|
352
|
+
explicit flag wins). Prefer the env var for the password so it doesn't land in shell history or the
|
|
353
|
+
process list:
|
|
354
|
+
|
|
355
|
+
```sh
|
|
356
|
+
export NEO4J_URI=bolt://localhost:7687
|
|
357
|
+
export NEO4J_PASSWORD=secret
|
|
358
|
+
cants --input ./my-ts-project --emit neo4j # credentials picked up from the environment
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Schema contract
|
|
362
|
+
|
|
363
|
+
`--emit schema` writes the machine-readable, version-stamped Neo4j schema (`schema.json`: node
|
|
364
|
+
labels, relationships, properties, constraints, and indexes). It needs no project and is bundled in
|
|
365
|
+
every release (as a wheel asset and a GitHub Release asset), so a consumer can validate
|
|
366
|
+
producer/consumer compatibility without invoking the binary.
|
|
367
|
+
|
|
368
|
+
```sh
|
|
369
|
+
cants --emit schema # print to stdout
|
|
370
|
+
cants --emit schema --output ./out # → ./out/schema.json
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## Development
|
|
374
|
+
|
|
375
|
+
This project uses [Bun](https://bun.sh/) as its toolchain.
|
|
376
|
+
|
|
377
|
+
```sh
|
|
378
|
+
bun install
|
|
379
|
+
bun run start -- --input /path/to/project # run from source
|
|
380
|
+
bun run typecheck # type-check
|
|
381
|
+
bun test # tests (the Neo4j bolt test is opt-in; see below)
|
|
382
|
+
bun run test:container # Neo4j bolt tests — needs Docker/Podman (opt-in)
|
|
383
|
+
bun run gen:schema # regenerate schema.neo4j.json
|
|
384
|
+
bun run gen:readme # regenerate the cants --help block above
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## License
|
|
388
|
+
|
|
389
|
+
Apache 2.0 — see [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
codeanalyzer_typescript/__init__.py,sha256=yjjO6E6NHQH_VDGqD_Zsyx8XR4psjlzrQVQFENtSFUg,2734
|
|
2
|
+
codeanalyzer_typescript/__main__.py,sha256=f8C3GgPB5RutSyYkwjas31c3M0zae5sKeudYWXHuQIg,1054
|
|
3
|
+
codeanalyzer_typescript/_bin/.gitignore,sha256=_mZ_61eDWQ65V05VrmLP33rSeppQmwCwV8_qsgHUOHM,251
|
|
4
|
+
codeanalyzer_typescript/_bin/cants,sha256=fc-eed0xnqIA7mqu4QALrwh4E3m4aZtAiojN-xglkHI,76972146
|
|
5
|
+
codeanalyzer_typescript/_bin/schema.json,sha256=5eX2C8DxsZQoN3UXa5NptZZItqbGeqh_Of484JR02Sw,13379
|
|
6
|
+
codeanalyzer_typescript-1.4.0.dist-info/METADATA,sha256=XsBFOyjNbWBv8VdlaAwursFpFhtc3pEtM1KXqDIPlXc,19798
|
|
7
|
+
codeanalyzer_typescript-1.4.0.dist-info/WHEEL,sha256=DaKw4g5QhaGEJdGocOieQE7NrIV0L6BFOhZh6JlDrJk,102
|
|
8
|
+
codeanalyzer_typescript-1.4.0.dist-info/entry_points.txt,sha256=-kWzUa53_kUEbiwup53Q5GqeSOdQM1iIRJHzPIwV7S0,64
|
|
9
|
+
codeanalyzer_typescript-1.4.0.dist-info/RECORD,,
|