From a93507a17bf1ce923d0e3db85bf2f08a8ca5e138 Mon Sep 17 00:00:00 2001 From: Rahul Krishna Date: Sun, 6 Sep 2026 19:47:45 -0400 Subject: [PATCH 1/7] =?UTF-8?q?docs:=20fix=20the=20logo=20on=20PyPI=20?= =?UTF-8?q?=E2=80=94=20raw=20URL,=20and=20the=20variant=20that=20reads=20o?= =?UTF-8?q?n=20white?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The README pointed at a GitHub /blob/ URL, which serves an HTML page rather than an image. GitHub rewrites that in its own renderer, so it looked right in the repository and was broken everywhere else, PyPI included. Two things were wrong. The URL is now the raw one. And the asset was the dark-mode variant — mean luminance 180/255, drawn to sit on a dark background — while PyPI's page is white, so fixing only the URL would have traded a broken image for an invisible one. A gives both: PyPI's renderer keeps the inner and strips , so PyPI gets the light-background logo while GitHub still switches on the reader's theme. Verified through readme_renderer, the renderer PyPI itself uses. --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c610d1cb..44f672c3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -Codellm-Devkit logo + + + Codellm-Devkit logo +

From 99035e418c8bffe42499ac0cb8081e221b7bb547 Mon Sep 17 00:00:00 2001 From: Rahul Krishna Date: Thu, 10 Sep 2026 14:33:03 -0400 Subject: [PATCH 2/7] =?UTF-8?q?docs(spec):=20java=203.2.0=20text=20model?= =?UTF-8?q?=20=E2=80=94=20the=20Neo4j=20projection=20catches=20up=20to=20i?= =?UTF-8?q?ts=20own=20JSON?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The canonical schema has mandated one `source` blob per module with byte offsets on every span since v2 was written, and `analysis.json` has carried it since 3.1.0 — measured on the committed a4 fixture, which holds `module.source` and `span.bytes` throughout and no `code` key on a callable. Only the Neo4j projection was lagging, and the backend compensated with `_ProjectedText` and a span that writes `bytes=(-1, -1)`. So 3.2.0 is a conformance fix, not a schema evolution: no new model fields, no change to the local backend, and the whole diff lands in the Java Neo4j read path. Four decisions recorded, with the cost of the first stated rather than buried: the floor moves to 3.2.0, which refuses every 3.1.x graph; the sibling analyzers are non-conformant the same way and get their own issues; one work item on `2.0.0rc6`; and the graph stops reading `:JCallable.code`, which turns the parity test's `endswith` into an equality. Closes-spec-for: #394 --- .../specs/2026-09-10-java-3.2.0-text-model.md | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 docs/design/specs/2026-09-10-java-3.2.0-text-model.md diff --git a/docs/design/specs/2026-09-10-java-3.2.0-text-model.md b/docs/design/specs/2026-09-10-java-3.2.0-text-model.md new file mode 100644 index 00000000..edd28b1c --- /dev/null +++ b/docs/design/specs/2026-09-10-java-3.2.0-text-model.md @@ -0,0 +1,142 @@ +# Java 3.2.0 text model: the Neo4j projection catches up to its own JSON + +**Status:** decided 2026-09-10. Single repo (`python-sdk`), one work item, `2.0.0rc6`. + +## Contract-Impact Triage + +**Does this change the schema v2 output? No — it makes the Java Neo4j projection *conform* to it.** + +The canonical schema has mandated this text model since v2 was written +(`cldk-devtools/skills/designing-cldk-changes/references/canonical-schema.md`): + +> Source text is stored **once per file, on the module node**, as `source`, and every node's text is +> a **slice** of it. […] To make slicing O(1), **spans carry byte/char offsets** alongside +> `line:col`. […] it subsumes any per-callable `code` field. + +`module.source` is listed there as **level 1, cardinality 1** — mandatory. `span` is +`{start, end, bytes}`, which is `JSpan` in `cldk/models/java/models.py` already. + +**Measured, not assumed:** `analysis.json` has conformed since **3.1.0**. The committed a4 fixture +(`tests/resources/java/analysis_json/v2/a4/analysis.json.gz`, `analyzer.version == "3.1.0"`) carries +`module.source` (8792 bytes on the first module), `span.bytes` on module / type / callable, a +`body_span` with its own byte pair, and **no `code` key on a callable at all**. The local backend +therefore already implements the consumer rule: `_Spanned._slice(span)` → `JCompilationUnit.slice` +→ `source_bytes[b0:b1].decode("utf-8")`. + +So the flat `start_byte` / `end_byte` / `body_start_byte` properties in 3.2.0 are the **Neo4j +projection flattening `span.bytes`** (Neo4j has no nested properties), not new schema fields. That +`grep start_byte cldk/models/` returns nothing is correct and stays correct. + +| Change type | Analyzers | SDKs | Docs | +| --- | --- | --- | --- | +| Schema v2 **conformance** (text model) | `codeanalyzer-java` 3.2.0 (done upstream) | `python-sdk` — Neo4j path only | `docs/agent-api-reference.md` | + +**Local `JCodeanalyzer`: zero changes.** The entire change is +`cldk/analysis/java/neo4j/{neo4j_backend,reconstruct}.py`. + +### What 3.2.0 projects + +Carries literal text: `:JModule.source` (whole file, 141/141), `:Artifact.source` (242/242, +truncated at `--artifact-text-max-bytes`, default 262144; absent under `--no-artifact-text`), +`:JCallable.code` (1127 rows, retained as a courtesy and **not** a general rule). + +Sliceable, via `start_byte`/`end_byte` into the owning module's `source`: `:JField` 659/659, +`:JVariable` 863/863, `:JType` 152/152; `:JCallable` 1127/1229 with `body_start_byte` on 1097; +`:JBodyNode` 6726/13544. The annotation *application*'s position rides `J_ANNOTATED_BY` +(817 edges with `start_byte` + `_k`). + +Never text, and each already accounted for on this side: + +| Category | Rows | Why the SDK is unaffected | +| --- | --- | --- | +| synthetic body vertices (`actual_in`/`formal_in`/`entry`/`exit`/`actual_out`/`formal_out`) | 6818 | `reconstruct` rebuilds only `call` nodes (~30%); the port lattice is not rebuilt at all | +| `@external` callables | 1205 | no module, no file — and they stay **in scope** by design (`can:///`, not `can:///java/`), so they must degrade, never raise | +| synthesized implicit `()` | 102 | already `is_implicit`, projected only when true; never written in source, so no text exists to want | +| `:JAnnotation` / `:JPackage` / `:ConfigKey` / `:JApplication` | 480 | shared-vocabulary nodes, deduped across use sites, so no single position | + +`1229 - 1127 = 102` — the callables without offsets are **exactly** the implicit constructors. There +is no callable whose text `:JCallable.code` can supply and a slice cannot. + +## Decisions + +**D1 — the analyzer floor moves to 3.2.0.** `_ANALYZER_FLOOR` (`neo4j_backend.py:216`) goes from +`(3, 1, 1)` to `(3, 2, 0)`. The mechanism already exists: `_probe_schema` reads +`:JApplication.analyzer_version` and refuses below the floor, naming what it found. + +*Cost, recorded because it was weighed and accepted:* a 3.1.x graph is refused at attach rather than +answering with `""` text and an honest lossiness note. Every live Java Neo4j suite needs its graph +re-emitted by 3.2.0 before it can run — they are `skipif`-gated on `CLDK_TEST_NEO4J_*`, so the +offline suite stays green either way, but the live evidence is unavailable until the re-emit. + +*Why a version check and not a data probe*, given the house rule that a probe reads the data: the +floor is a **generation** question, not a capability one. `_probe_schema`'s docstring already +records the precedent — a 3.1.0 graph carries every relationship type the probe looks for and then +answers every prefix-scoped statement with zero rows, so version was the only thing between a caller +and a silent empty. `:JModule.source` is a fine capability probe and a poor generation probe. + +**D2 — Java only; the siblings are follow-ups.** `codeanalyzer-python` and `codeanalyzer-typescript` +are non-conformant the same way, and the SDK compensates for each with a documented fiction: + +| Analyzer | The compensation | +| --- | --- | +| `codeanalyzer-typescript` | `typescript/neo4j/reconstruct.py:91` fabricates `bytes=(0, len(code))` — an offset into the *node's own text*, not into the module source; `_with_code` at `:94` | +| `codeanalyzer-python` | `python/neo4j/neo4j_backend.py:2075` — `source=cprops.get("code") or ""` | + +Both get their own issue on their own repo once this lands. No epic: they ship on their own clocks +and share no PR with this change. + +**D3 — one work item, `2.0.0rc6` off `release/2.0`.** One PR closes it; the rungs are checkboxes. + +**D4 — the graph stops reading `:JCallable.code`.** Slice only. This is what closes the parity +divergence: `cldk/analysis/java/backend.py:538-544` compares the two backends with +`neo.code.endswith(ref.code)` *because* the graph's `code` is the whole declaration where the local +backend's is the body block. With `body_start_byte` the graph slices the body block too, and the +assertion becomes an equality. + +`_ProjectedText` (`reconstruct.py:104-123`) — the stand-in whose `slice()` deliberately ignores the +span — is deleted, and with it `thread_code` and `_projected_code` (`neo4j_backend.py:591-602`). + +## Work + +- [ ] `_ANALYZER_FLOOR` → `(3, 2, 0)`, docstring rewritten to say what 3.2.0 is the floor *for*. +- [ ] `reconstruct.span()` reads `start_byte`/`end_byte` into `JSpan.bytes`; `_UNKNOWN` survives only + for the nodes that genuinely carry no offsets. +- [ ] `:JModule.source` threaded onto the reconstructed `JCompilationUnit`. Read as + `props.get("source", "")`, **the deliberate exception** to the contract that every non-boolean + property is read with `props[...]`: an unreadable or non-UTF-8 file means "no text for this + whole file", degrading per module rather than raising per node. +- [ ] `JCallable.body_span` rebuilt from `body_start_byte`. **Measure first** whether the callable's + own `end_byte` closes the body block; the briefing gives no `body_end_byte`, and guessing + silently truncates or over-reads every method body. +- [ ] Delete `_ProjectedText`, `thread_code`, `_projected_code`. +- [ ] `J_ANNOTATED_BY.start_byte` + `_k` → the annotation application's span. +- [ ] `backend.py:538-544`: `endswith` → equality, with the reason updated. +- [ ] `conftest.py:89` fake-driver default `analyzer_version` → `"3.2.0"`; the + `test_java_schema_probe.py` above/below parametrizations and its `match="3.1.1 or newer"`. +- [ ] Rewrite the four measured lossiness entries in `reconstruct.py`'s module docstring + (`:35-39`, `:40-49`, `:51-53`) and the matching text in `neo4j_backend.py:94-98` and + `docs/agent-api-reference.md`. Each was measured against a live graph; each is re-measured, not + edited by inference. +- [ ] Pin `codeanalyzer-java==3.2.0` (`pyproject.toml:46`, `:89`). `release.yml` fetches + `releases/tags/v` and requires exactly `codeanalyzer-.jar`, so the pin is the only + place the jar version is stated. + +## Caveats + +- **`body_end_byte` is not in the projection's inventory.** Assuming the declaration's `end_byte` + closes the body is plausible and unverified. Measure it. +- **`:JModule.source` has no truncation flag.** `:Artifact.source` has `text_truncated` and + `extraction`; a module has neither in the inventory. If a large file can be truncated silently, a + slice past the cut reads as empty rather than as unavailable — the one failure shape that looks + like data instead of a gap. Confirm upstream before trusting a slice's tail. +- **`:JBodyNode` is 6726/13544 — under half.** The guard is not decoration. `reconstruct` rebuilds + only `call` nodes today, so the exposure is smaller than the ratio suggests, but the rule holds: + check the offsets exist, never assume them from the node kind. + +## Definition of done + +The offline suite is green with no live server. A 3.1.2 graph is refused at attach by version, +naming the floor. On a re-emitted 3.2.0 daytrader8 graph: `JField` / `JVariable` / `JType` / +`JBodyNode` return real text where they returned `""`; a method body off the graph **equals** the +same method body off `analysis.json`; and a callable with no offsets (an implicit `()`) and an +`@external` callable both return an empty text without raising. From 51bdb2e3b7e558c621d27cc4714543e979e8748f Mon Sep 17 00:00:00 2001 From: Rahul Krishna Date: Thu, 10 Sep 2026 16:50:07 -0400 Subject: [PATCH 3/7] feat(java): consume codeanalyzer-java 3.2.0's text model in the Neo4j read path The Neo4j projection now carries the same text model analysis.json has carried since 3.1.0: :JModule.source holds each file whole, and a start_byte/end_byte pair reaches :JType, :JField, :JVariable, :JCallable (plus body_start_byte) and :JBodyNode. Every node's code becomes a slice of its own module, so the graph answers the same text as the local backend at every granularity -- down to a single statement, which had no text over Neo4j at all. The read path: * _ANALYZER_FLOOR moves to (3, 2, 0). A 3.1.x graph carries text only as :JCallable.code and no offsets, so every other node's code would rebuild as "" -- served silently as though the file held nothing. Refused, not degraded. * reconstruct.span()/body_span() read the flat offsets into JSpan.bytes, both or neither: (b0, -1) would slice to one byte before EOF, which is a wrong answer where (-1, -1) is an empty one. * compilation_unit reads source with .get, the deliberate exception to the props[...] rule -- a file the analyzer could not read or decode degrades per module, not per attach. * _BODY_NODES projects sb/eb and _body_nodes() threads each node's owning unit, because a :JBodyNode has no id to recover its owner from. * JCallable.code slices body_span or span; code_start_line keeps its fallback, since backend.py's callable-relative arithmetic adds an offset to it and must never get -1 where it used to get a line. * _ProjectedText, thread_code and _projected_code are deleted, and :JCallable.code is no longer read at all. body_end_byte is not needed and that is measured, not assumed: 1182 callables across both committed fixtures carry both spans and none has body_span.bytes[1] != span.bytes[1] -- a Java declaration's last character is its body's closing brace. The offline fixture asserts it on every run. Tests: the offline seeded and fake graphs now carry real module text and derived byte offsets, so the byte-offset and slice paths are exercised rather than passing vacuously on (-1, -1); the implicit (), the synthetic entry node and the $anon$0 probes stay offset-free to keep the no-text branches covered. The live parity suites assert equality where they tolerated endswith. The schema probe moves a generation: 3.1.2 is now the release immediately below the floor. Docs: the analyzer floor table and four text-lossiness entries are re-measured down to one "text is the same on both backends" entry, keeping the three cases that genuinely have no text -- an implicit callable, an @external callable and a dataflow vertex. codeanalyzer-java pinned to 3.2.0. Spec: docs/design/specs/2026-09-10-java-3.2.0-text-model.md Closes #394 --- CLAUDE.md | 2 +- cldk/analysis/commons/results.py | 8 +- cldk/analysis/java/backend.py | 63 +++--- cldk/analysis/java/neo4j/neo4j_backend.py | 102 ++++++---- cldk/analysis/java/neo4j/reconstruct.py | 186 ++++++++++-------- cldk/models/java/models.py | 33 ++-- docs/agent-api-reference.md | 73 +++---- pyproject.toml | 4 +- tests/analysis/java/conftest.py | 2 +- tests/analysis/java/test_java_addressing.py | 32 +-- .../java/test_java_addressing_live.py | 44 +++-- .../java/test_java_entrypoints_live.py | 6 +- .../analysis/java/test_java_neo4j_backend.py | 51 ++--- ...test_java_neo4j_multi_application_scope.py | 123 ++++++++++-- tests/analysis/java/test_java_neo4j_scale.py | 10 +- tests/analysis/java/test_java_schema_probe.py | 27 +-- .../java/test_java_v1_accessors_live.py | 15 +- uv.lock | 6 +- 18 files changed, 473 insertions(+), 314 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 93f412c1..95db528f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,7 +10,7 @@ an optional read-only Neo4j backend — selected by the *type* of the `backend=` | Language | Entry point | Local backend | Neo4j backend | Models | |----------|-------------|---------------|---------------|--------| -| Java | `CLDK.java(...)` (needs the `cldk[java]` extra) | `JCodeanalyzer` (the `codeanalyzer-java` 3.1.1 wheel's jar on its bundled JVM, subprocess, `-a 1..4` — no jar in this repo, no JDK download) | `JNeo4jBackend` (graphs emitted by ≥ 3.1.1, probed at attach) | `cldk/models/java/` (schema v2 mirror) + `projections.py` | +| Java | `CLDK.java(...)` (needs the `cldk[java]` extra) | `JCodeanalyzer` (the `codeanalyzer-java` 3.2.0 wheel's jar on its bundled JVM, subprocess, `-a 1..4` — no jar in this repo, no JDK download) | `JNeo4jBackend` (graphs emitted by ≥ 3.2.0, probed at attach) | `cldk/models/java/` (schema v2 mirror) + `projections.py` | | Python | `CLDK.python(...)` | `PyCodeanalyzer` (in-process `codeanalyzer-python`) | `PyNeo4jBackend` | re-exported from `codeanalyzer-python` | | TypeScript (+ JavaScript modules) | `CLDK.typescript(...)` | `TSCodeanalyzer` (`codeanalyzer-typescript` 1.5.2 binary from the wheel, subprocess; `-a 1..4`, but `--emit neo4j` takes no `-a` and is always full depth) | `TSNeo4jBackend` (graphs emitted by ≥ 1.5.2; older refused at attach) | `cldk/models/typescript/` (schema v2 mirror) | diff --git a/cldk/analysis/commons/results.py b/cldk/analysis/commons/results.py index e1babf00..d017b226 100644 --- a/cldk/analysis/commons/results.py +++ b/cldk/analysis/commons/results.py @@ -273,9 +273,11 @@ class SliceNode(BaseModel): defined_in: For a ``global``, the module it is defined in (``"payment"``) — the same vocabulary as :attr:`ModuleRef.module_name`. ``None`` for everything else, whose defining scope is the enclosing callable in :attr:`callable`. - source: The text, when the backend can produce it; ``None`` when it cannot. The Neo4j graph - carries no text below callable granularity (see :class:`LocateResult`), so it is - ``None`` there for anything finer. + source: The text, when the backend can produce it; ``None`` when it cannot. Whether a + Neo4j graph carries text below callable granularity is the projection's choice, so it + depends on the language: Java's does since codeanalyzer-java 3.2.0 and answers the same + text as its local backend, Python's does not and is ``None`` there for anything finer + (see :class:`LocateResult`). ref: The analyzer's own id for this node — **opaque**. Pass it back; do not parse it, and do not build one. The one sanctioned use is :meth:`~cldk.analysis.python.backend.PythonAnalysisBackend.get_source`, and that diff --git a/cldk/analysis/java/backend.py b/cldk/analysis/java/backend.py index 8b41975a..7e7827d9 100644 --- a/cldk/analysis/java/backend.py +++ b/cldk/analysis/java/backend.py @@ -531,16 +531,16 @@ class JavaAnalysisBackend(AnalysisBackend[JApplication, JCompilationUnit, JType, # callable (:meth:`_body_nodes`), the text of one (:meth:`_body_source`), and whether call # sites resolve at all (:attr:`has_resolution_edges`). # - # WHAT STILL DIFFERS, AND IT IS THE DATA, NOT THE CODE. ``JCallable.code`` is the **body - # block** off ``analysis.json`` and the whole **declaration** off the Neo4j projection - # (codeanalyzer-java#176: the graph carries one line range per callable and no ``body_span``), - # so :meth:`get_source` and :attr:`LocateResult.source` return the declaration over Neo4j — - # stated on :meth:`JavaAnalysis.get_source`, in the lossiness table of - # ``docs/agent-api-reference.md``, and asserted by the live parity suite as - # ``neo.code.endswith(ref.code)``. A **module** carries no ``source`` at all there, so a - # module-scope :meth:`locate` answers ``""`` plus a ``module_source_unavailable`` diagnostic; - # and a body node has no text on either side of the graph, so it hydrates only locally. - # None of that is branched on: it falls out of what the models hold. + # WHAT STILL DIFFERS, AND IT IS THE DATA, NOT THE CODE. **Text no longer differs.** + # codeanalyzer-java 3.2.0 projects ``:JModule.source`` plus the byte offsets every node's text is + # a slice of, so :meth:`get_source`, :attr:`LocateResult.source` and a module-scope + # :meth:`locate` read the same characters on both backends and the live parity suite asserts + # ``neo.code == ref.code`` (it asserted ``neo.code.endswith(ref.code)`` while the graph carried + # the whole declaration and no ``body_span`` — codeanalyzer-java#176, fixed by the 3.2.0 text + # model, which is why ``JNeo4jBackend`` floors there). What is still thinner over Neo4j is the + # *set* of nodes, not their text: a body node has text only where the projection wrote offsets + # for it, and ``JCallable.body`` holds the ``call`` nodes only. None of that is branched on: it + # falls out of what the models hold. # # NO ``can://`` AND NO ORDINAL leaves this surface except in ``ref`` / ``node_id`` (E6/E7); # every error names what missed and suggests nothing (E8). @@ -651,9 +651,10 @@ def _locate_result(self, line: int, key: str, row: Optional[_Addressed], bodies: names = java_module_dotted(unit.package, unit.types) module_ref = ModuleRef(path=key, module_name=names[0] if names else None) if row is None: - # The graph carries no module ``source``, so the text a module-scope result would hand - # back does not exist there. Read off the data rather than off which backend is running: - # "" is never returned as if it were the file. + # Read off the data rather than off which backend is running: "" is never returned as + # if it were the file. Since codeanalyzer-java 3.2.0 the projection carries + # ``:JModule.source``, so this diagnostic fires on a module whose text is genuinely + # missing -- an unreadable or undecodable file -- and on nothing else. diagnostics = [Diagnostic(code="module_scope", message=f"line {line} is at module scope in {key}.")] if not unit.source: diagnostics.append(Diagnostic(code="module_source_unavailable", message=f"no source text is available for {key} on this backend.")) @@ -823,17 +824,17 @@ def get_source(self, node_id: str) -> str: statement or call site an alert landed on can be re-fetched, not just its enclosing callable. Round-tripped, never composed by the caller (E6). - **What comes back for a callable differs by backend, and the difference is the graph's.** - Off ``analysis.json`` it is the **body block**; off the Neo4j projection it is the whole - **declaration**, which ends with that body block — the graph carries one line range per - callable and no ``body_span`` (codeanalyzer-java#176). The relation is exact and total, and - the live parity suite asserts it rather than tolerating it. + **The same text on both backends**: the callable's body block, or the statement's own + region, sliced out of the module's text. Before codeanalyzer-java 3.2.0 the graph carried + one line range per callable, no ``body_span`` and no module text, so a callable came back as + the whole **declaration** and a body node not at all (codeanalyzer-java#176); 3.2.0 projects + ``:JModule.source`` plus byte offsets down to ``:JBodyNode``, and the live parity suite + asserts equality rather than tolerating a difference. Raises: KeyError: Nothing this backend holds is named by ``node_id``, or it names a node with - no recoverable text — an implicit callable (no span and no body at all), or, on the - Neo4j backend, any body node, since the graph carries no text below callable - granularity. The message names the reason. + no recoverable text — an implicit callable (no span and no body at all), or any + node the projection placed nowhere in a file. The message names the reason. """ found = self._sources_for([node_id]) if node_id not in found: @@ -904,11 +905,10 @@ def describe(self, nodes: Sequence[object]) -> List[SliceNode]: Afterwards ``source=None`` means exactly one thing: *this position exists and the backend has no text for it*. It never means "the lookup failed", because a ref naming nothing raises - instead. Which positions have no text differs by backend, honestly: a ``kind="callable"`` - node hydrates on both (as the declaration over Neo4j, the body block locally); a - ``parameter`` hydrates on neither, having no span in the analyzer's own model; a statement - or call site hydrates only locally, because the graph carries no text below callable - granularity. + instead. Which positions have no text no longer differs by backend: a ``kind="callable"`` + node and a statement or call site both hydrate on either, to the same slice of the same file + (codeanalyzer-java 3.2.0 carries byte offsets down to ``:JBodyNode``); a ``parameter`` + hydrates on neither, having no span in the analyzer's own model. Raises: KeyError: A ``ref`` names nothing this backend can find — a ref comes from this SDK, so @@ -1381,9 +1381,8 @@ def get_methods_with_annotations(self, annotations: List[str]) -> Dict[str, List Neither sibling language has this accessor, so it is designed rather than ported, and the pattern it follows is :meth:`JavaAnalysis.get_test_methods`: read the **analyzer's own** annotations off the model (``J_ANNOTATED_BY``; 26,162 edges on the reference graph) rather - than re-parsing a source string, so it answers identically on both backends -- a - Neo4j-backed analysis carries no module source at all, and the 1.x tree-sitter version - returned ``{}`` there. + than re-parsing a source string, so it answers identically on both backends -- the 1.x + tree-sitter version returned ``{}`` on any projection that carried no module text. Args: annotations: Annotation names, matched by the J-5 marker rule @@ -1401,10 +1400,8 @@ def get_methods_with_annotations(self, annotations: List[str]) -> Dict[str, List * ``class`` -- the declaring type's qualified name; * ``signature`` -- the callable's signature within that type; * ``method_name`` -- its simple name (the 1.x key, kept); - * ``body`` -- :attr:`~cldk.models.java.models.JCallable.code` (the 1.x key, kept). - Note this is the body block off ``analysis.json`` and the whole declaration off the - Neo4j projection, exactly as it is for :meth:`JavaAnalysis.get_test_methods`; it is a - documented property of the model, not a divergence introduced here. + * ``body`` -- :attr:`~cldk.models.java.models.JCallable.code` (the 1.x key, kept), + the body block on either backend since codeanalyzer-java 3.2.0. ``class`` and ``signature`` are new against 1.x, which returned the simple name alone. A simple name is not an address in Java -- 200 of daytrader8's 581 distinct signatures diff --git a/cldk/analysis/java/neo4j/neo4j_backend.py b/cldk/analysis/java/neo4j/neo4j_backend.py index 2655d07f..cedefc70 100644 --- a/cldk/analysis/java/neo4j/neo4j_backend.py +++ b/cldk/analysis/java/neo4j/neo4j_backend.py @@ -21,7 +21,7 @@ surface, answered over a live graph that ``codeanalyzer-java --emit neo4j`` populated out of band. This class never writes and needs neither the analyzer JAR, a JDK, nor the project sources. -**The graph it reads** (``schema.neo4j.json`` at the 3.1.1 tag, contract ``2.0.0``, verified +**The graph it reads** (``schema.neo4j.json`` at the 3.2.0 tag, contract ``2.0.0``, verified against the reference graph): ``:JApplication`` is keyed by **``id``** (``can://``; ``name`` survives as a display property with no uniqueness constraint) and stamps ``analyzer_version``; every project-owned node carries a ``can:///java/…`` ``id`` and the @@ -90,10 +90,13 @@ are not issued at all (:meth:`_overlay_rows`). **Lossiness** relative to the in-memory backend (the projection's, not this client's; see -:mod:`reconstruct` for the per-node detail): a module carries no ``source`` and no span, so -``JCompilationUnit.code`` is ``""`` and only a *callable's* text survives — as its whole -declaration, where the local backend's ``code`` is the body block; comments exist only as one -``docstring`` per declaration, so file-level comments are not projected at all +:mod:`reconstruct` for the per-node detail): **text is no longer part of it** — codeanalyzer-java +3.2.0 projects ``:JModule.source`` plus byte offsets, so every node's ``code`` is the same slice of +the same file the local backend reads, a callable's included (its ``body_span`` is rebuilt from +``body_start_byte``, so ``code`` is the body block on both backends); what remains missing is every +*column*, a slice for the 102 implicit ``()`` that were never written, and text below the +``call`` nodes of a body. Comments exist only as one ``docstring`` per declaration, so file-level +comments are not projected at all (:meth:`get_all_comments` and :meth:`get_comment_in_file` raise rather than answer with a smaller set claiming to be every comment); ``JCallable.body`` holds the ``call`` nodes only, without their ``arguments`` or end columns; ``cfg``/``cdg``/``ddg``/``summary``, ``param_in``/``param_out`` and @@ -205,15 +208,23 @@ class JNeo4jBackend(JavaAnalysisBackend): #: Relationship types every supported graph has; a graph missing any was emitted by another #: generation (a schema-v1 graph shares only ``J_CALLS``) and is refused at attach. _REQUIRED_RELATIONSHIP_TYPES: FrozenSet[str] = frozenset({"J_HAS_MODULE", "J_HAS_METHOD", "J_HAS_BODY_NODE", "J_CALLS"}) - #: The oldest codeanalyzer-java whose graph this backend serves. **3.1.1 exactly**, not - #: "3.0.1 or newer": 3.1.1 moved the application to the outermost segment of the ``can://`` + #: The oldest codeanalyzer-java whose graph this backend serves. **3.2.0 exactly** — the release + #: whose projection carries the canonical text model: ``:JModule.source`` plus the + #: ``start_byte``/``end_byte`` offsets every node's ``code`` is a slice of. This backend reads + #: text only that way (:func:`reconstruct.span`), so on a 3.1.x graph every ``code`` on every + #: node would be ``""`` — the silent empty this floor exists to refuse. + #: + #: *Why a version and not a data probe*, against the house rule that a probe reads the data: the + #: floor is a **generation** question, not a capability one, and the precedent is the reason 3.1.1 + #: was the floor before it. 3.1.1 moved the application to the outermost segment of the ``can://`` #: grammar every statement here scopes on, and 3.1.0 — which is in the wild — emits the old - #: ``can://java//…`` one. A 3.1.0 graph carries every relationship type + #: ``can://java//…`` one; a 3.1.0 graph carries every relationship type #: :meth:`_probe_schema` looks for and the contract-2.0.0 body-node shape, so it attaches - #: cleanly and then answers every prefix-scoped statement with zero rows. Refusing it by version - #: is the only thing between a caller and that silent empty. (3.0.0 stamped contract 2.2.0; - #: 3.0.1 holds 2.0.0 — the body-node shape every statement here reads.) - _ANALYZER_FLOOR = (3, 1, 1) + #: cleanly and then answers every prefix-scoped statement with zero rows. Version was the only + #: thing between a caller and that empty then, and ``:JModule.source`` is a fine capability probe + #: and a poor generation one now. (3.0.0 stamped contract 2.2.0; 3.0.1 holds 2.0.0 — the + #: body-node shape every statement here reads.) + _ANALYZER_FLOOR = (3, 2, 0) #: Set by :meth:`_probe_schema`; the class-level ``None`` is for the ``object.__new__`` seam. _analyzer_version: Tuple[int, int, int] | None = None #: The database's relationship types, read once by :meth:`_probe_schema` and reused by @@ -559,9 +570,7 @@ def _reconstruct(self) -> JApplication: # A module declares types only; ``kind`` is a ``Literal`` on :class:`JType`, so a # row that is not one is refused by the model. types[self._child_key(module_id, p)] = self._type(p, children, sites) - unit = R.compilation_unit(props, import_declarations=[i for e in imports.get(key, []) for i in R.imports(e)], types=types) - R.thread_code(unit, self._projected_code(children, module_id)) - symbol_table[key] = unit + symbol_table[key] = R.compilation_unit(props, import_declarations=[i for e in imports.get(key, []) for i in R.imports(e)], types=types) return JApplication( id=self._application_id, symbol_table=symbol_table, @@ -587,20 +596,6 @@ def _reconstruct(self) -> JApplication: config_reads_unresolved=None if report is None else reads, ) - @staticmethod - def _projected_code(children: Dict[str, List[_Child]], module_id: str) -> Dict[str, str]: - """``callable id -> code`` for one module's subtree — what :func:`reconstruct.thread_code` - threads onto the callables so their ``code`` view reads the graph's text.""" - out: Dict[str, str] = {} - stack = [module_id] - while stack: - for rel, p, _ in children.get(stack.pop(), []): - if rel in ("J_DECLARES", "J_HAS_METHOD"): - stack.append(p["id"]) - if rel == "J_HAS_METHOD": - out[p["id"]] = p.get("code") or "" - return out - # ===================================================================================== # The reconstructed view and its index (both built on first use) # ===================================================================================== @@ -697,7 +692,8 @@ def _callables(self) -> Dict[str, Tuple[JType, JCallable]]: _BODY_NODES = ( "UNWIND $prefixes AS p MATCH (b:JBodyNode) WHERE b.id STARTS WITH p " "OPTIONAL MATCH (b)-[:J_RESOLVES_TO]->(t) WHERE " + _scoped("t") + " " - "RETURN b.id AS id, b.kind AS kind, b.start_line AS s, b.end_line AS e, t.id AS callee" + "RETURN b.id AS id, b.kind AS kind, b.start_line AS s, b.end_line AS e, " + "b.start_byte AS sb, b.end_byte AS eb, t.id AS callee" ) def _body_nodes(self, callable_ids: Sequence[str]) -> Dict[str, Dict[str, JBodyNode]]: @@ -708,6 +704,12 @@ def _body_nodes(self, callable_ids: Sequence[str]) -> Dict[str, Dict[str, JBodyN Java ``can://`` id carries none (checked: 0 of daytrader8's 1,216 and ThingsBoard's 28,763 callables). That recovers the *callable*, which is all that is needed here; it does not recover the local body key, and nothing tries to. + + Each node is then threaded to the compilation unit that callable was declared in, which is + what makes :meth:`_body_source` a real slice: these nodes are built outside the containment + tree, so :meth:`JCompilationUnit.model_post_init` never sees them. A callable with no unit + (an ``@external``, which stays in scope by design) leaves its nodes unthreaded, and + :meth:`_body_source` answers ``None`` for them. """ ids = list(dict.fromkeys(callable_ids)) if not ids: @@ -715,15 +717,34 @@ def _body_nodes(self, callable_ids: Sequence[str]) -> Dict[str, Dict[str, JBodyN out: Dict[str, Dict[str, JBodyNode]] = {} for row in self._run(self._BODY_NODES, prefixes=[f"{i}@" for i in ids], prefix=self._scope_prefix): node_id = row["id"] - out.setdefault(node_id.partition("@")[0], {})[node_id] = R.body_node({"kind": row["kind"], "start_line": row["s"], "end_line": row["e"], "callee": row["callee"]}, None) + owner = node_id.partition("@")[0] + node = R.body_node( + {"kind": row["kind"], "start_line": row["s"], "end_line": row["e"], "start_byte": row["sb"], "end_byte": row["eb"], "callee": row["callee"]}, + None, + ) + node._unit = self._unit_of(owner) + out.setdefault(owner, {})[node_id] = node return out + def _unit_of(self, callable_id: str) -> JCompilationUnit | None: + """The compilation unit a callable was declared in, or ``None`` when it has no file — which + is every ``@external`` callable, and nothing else.""" + owner = self._callables.get(callable_id) + return None if owner is None else self._application.symbol_table.get(self._file_of.get(owner[0].qualified_name, "")) + def _body_source(self, node: JBodyNode) -> str | None: - """See :meth:`JavaAnalysisBackend._body_source`. Always ``None``: ``:JBodyNode`` carries a - line range and no text, and ``:JModule`` carries no ``source`` to slice one out of, so this - projection has nothing below callable granularity. Substituting the enclosing callable's - declaration would be a wrong answer rather than a missing one.""" - return None + """See :meth:`JavaAnalysisBackend._body_source` — a real slice of the owning module's + ``source``, off the ``start_byte``/``end_byte`` codeanalyzer-java 3.2.0 projects on a + ``:JBodyNode`` and the unit :meth:`_body_nodes` threaded on. + + ``None`` — never ``""`` — for the two nodes that have no text here: one the projection wrote + no offsets for (6,726 of the reference graph's 13,544 carry them; the synthetic port + vertices stand for no source at all) and one whose callable has no file. An empty string + would claim the node's text *is* empty, which is the wrong answer rather than a missing one. + """ + if node._unit is None or node.span is None or node.span.bytes[0] < 0: + return None + return node.code or None @property def has_resolution_edges(self) -> bool: @@ -1188,11 +1209,10 @@ def get_all_constructors(self, qualified_class_name: str) -> Dict[str, JCallable return {sig: c for sig, c in klass.callables.items() if c.is_constructor} def get_method(self, qualified_class_name: str, qualified_method_name: str) -> JCallable | None: - """The callable, or ``None``. Two fields differ from the in-memory backend's, because the - projection differs: ``code`` is the whole **declaration** (the graph carries one line range - per callable and no ``body_span``), where the in-memory backend's is the body block; and - ``body`` holds the ``call`` nodes **only** — about 30% of the graph's body nodes (4,006 of - daytrader8's 13,436) — which is what ``call_sites`` is a view over.""" + """The callable, or ``None``. One field differs from the in-memory backend's, because the + projection differs: ``body`` holds the ``call`` nodes **only** — about 30% of the graph's + body nodes (4,006 of daytrader8's 13,436) — which is what ``call_sites`` is a view over. + ``code`` is the same body block on both since codeanalyzer-java 3.2.0.""" klass = self.get_class(qualified_class_name) return klass.callables.get(qualified_method_name) if klass is not None else None diff --git a/cldk/analysis/java/neo4j/reconstruct.py b/cldk/analysis/java/neo4j/reconstruct.py index ed71297f..f3cfbc52 100644 --- a/cldk/analysis/java/neo4j/reconstruct.py +++ b/cldk/analysis/java/neo4j/reconstruct.py @@ -14,11 +14,12 @@ # limitations under the License. ################################################################################ -"""Rebuild the ``cldk.models.java`` (schema v2) models from codeanalyzer-java 3.0.1 Neo4j node and -edge property maps. +"""Rebuild the ``cldk.models.java`` (schema v2) models from codeanalyzer-java Neo4j node and edge +property maps. Pure functions: they take the flat property dictionaries the analyzer's Neo4j projection wrote -(``schema.neo4j.json`` at the 3.0.1 tag is the authority for what each label carries) and return +(``schema.neo4j.json`` at the 3.2.0 tag -- the attach floor -- is the authority for what each label +carries; schema v2 itself landed at 3.0.1) and return the same pydantic objects the in-memory :class:`~cldk.analysis.java.codeanalyzer.JCodeanalyzer` returns. :class:`~cldk.analysis.java.neo4j.JNeo4jBackend` fetches the rows and assembles the containment tree; the per-node shape lives here. @@ -29,29 +30,31 @@ ``False`` in the contract, and reading one with a ``False`` default is not a default hiding drift. Every non-boolean property the contract declares on a label is read with ``props[...]``. +**Text is one blob per file, sliced by byte offsets** -- the canonical schema's model since v2, and +what codeanalyzer-java 3.2.0 finally projects. ``:JModule.source`` carries the whole file (141 of 141 +modules on the 3.2.0 reference graph) and every other node's ``code`` is +``source[start_byte:end_byte]``, which is what :meth:`JCompilationUnit.slice` does. Offsets are +projected on ``:JField`` (659/659), ``:JVariable`` (863/863), ``:JType`` (152/152), ``:JCallable`` +(1,127/1,229, plus ``body_start_byte`` on 1,097) and ``:JBodyNode`` (6,726/13,544); the annotation +*application*'s offsets ride ``J_ANNOTATED_BY`` (817 edges). The 102 callables without offsets are +**exactly** the synthesized implicit ``()`` -- never written, so there is no text to want -- +which is why no callable's text is reachable through a projected ``:JCallable.code`` and not through +a slice: this module reads that property no longer, and :func:`span` is the only text path. + What the projection does **not** carry, and therefore comes back at the model's own empty default (measured against the live graph, not assumed): -* **``JModule.source``** -- the graph stores each *callable's* own text in ``JCallable.code`` and - nothing else, so a reconstructed :class:`JCompilationUnit` has ``source=""``. Its ``span`` is - unknown too (``:JModule`` carries no lines at all), so it rehydrates as the model's own ``-1``. - A callable is pointed at the text the graph did project through :func:`thread_code`; every other - node's ``code`` is ``""``. -* **every column and every byte offset** -- the projection writes ``start_line`` and ``end_line`` - and no position within a line, and no offset into a ``source`` it does not carry. Both are - reported as :data:`_UNKNOWN` (``-1``), the model's own "not known", on every node: a ``0`` would - read as column one and offset zero, which is a position, and a wrong one. **One exception, and it - is deliberate:** a :class:`JCallableParameter` comes back with the analyzer's own columns *and* - byte offsets, because the projection serialises the whole parameter list into - ``:JCallable.parameters_json`` and it round-trips exactly (see :func:`parameters`). Those byte - offsets index the module ``source`` the graph does not carry, so they locate the parameter in the - file on disk and nothing this backend can hand you; ``JCallableParameter.code`` is unreachable on - either backend (a parameter is never threaded to its compilation unit, so slicing raises rather - than returning a silent empty). -* **``JCallable.body_span``** -- the graph projects one line range per callable, the *declaration* - span. So ``JCallable.code`` here is the whole declaration (``public void f() {…}``), where the - local backend's is the body block (``{…}``); ``code_start_line`` is the declaration's first line, - which is the body block's first line too except where the opening brace sits on a later line. +* **every column** -- the projection writes ``start_line``/``end_line`` and no position within a + line, so both columns are :data:`_UNKNOWN` (``-1``) on every node: a ``0`` would read as column + one, which is a position and a wrong one. **One exception, and it is deliberate:** a + :class:`JCallableParameter` comes back with the analyzer's own columns, because the projection + serialises the whole parameter list into ``:JCallable.parameters_json`` and it round-trips exactly + (see :func:`parameters`). Its byte offsets index the same module ``source`` as everything else, but + a parameter is never threaded to its compilation unit, so ``JCallableParameter.code`` raises on + either backend rather than returning a silent empty. +* **a module without ``source``** -- an unreadable or non-UTF-8 file. Nothing in the reference graph + is one, and the degradation is per *file* rather than per node: every node in that module slices + an empty string and reports ``""`` (see :func:`compilation_unit`). * **comments** -- there are no ``:JComment`` nodes (0 in the reference graph). A type, callable, field, enum constant and record component carries a single ``docstring`` property holding its javadoc, rebuilt here as a one-element ``comments`` list; a non-javadoc comment on a declaration, @@ -59,8 +62,9 @@ * **``JCallable.body``** -- only the ``call`` nodes are rebuilt (what ``call_sites`` is a view over), which is roughly **30%** of what the graph holds (4,006 of daytrader8's 13,436 ``:JBodyNode``); the ``entry``/``exit``/``statement``/``branch``/``loop``/``return`` nodes and the - parameter lattice are not. A call site's ``arguments`` (body-key references) and both columns are - not projected either. + parameter lattice are not. A call site's ``arguments`` (body-key references) are not projected + either. The 6,818 synthetic vertices of the port lattice carry no offsets and want none: none of + them stands for source text. * **``JBodyNode.callee``** (226 populated on the committed daytrader8 ``-a 4`` fixture, 0 here) -- the ``can://`` id of the resolved callee. The projection puts that edge on ``J_RESOLVES_TO``, which this module reads into ``callee_signature`` instead, and an id has no home on the public surface @@ -71,13 +75,13 @@ to a call site. It follows from the comment gap above: the graph has no comment node to attach. * ``cfg`` / ``cdg`` / ``ddg`` / ``summary`` (``None``: 3b reads them per callable on demand), ``type_parameters``, ``JCompilationUnit.comments``, ``JApplication.param_in`` / ``param_out`` / - ``external_symbols``, and a decorator's / import's / enum constant's / record component's span. + ``external_symbols``, and an import's / enum constant's / record component's span. """ from __future__ import annotations import json -from typing import Any, Dict, List, Mapping, Optional +from typing import Any, Dict, List, Mapping, Optional, Tuple from cldk.models.java.models import ( JArtifact, @@ -101,63 +105,66 @@ Props = Mapping[str, Any] -class _ProjectedText: - """Stands in for the owning :class:`JCompilationUnit` on a callable, so its ``code`` view reads - the text the graph projected for it. - - ``:JModule`` carries no ``source``, so a reconstructed unit can slice nothing; ``:JCallable`` - carries its own ``code``. The models reach the unit only through the private ``_unit`` - back-reference, and only for :meth:`JCompilationUnit.slice` and ``package`` -- so pointing a - callable at one of these is what turns ``JCallable.code`` from an empty slice into that text - (see :func:`thread_code`). - """ - - __slots__ = ("_code", "package") - - def __init__(self, code: str, package: str) -> None: - self._code, self.package = code, package - - def slice(self, span: JSpan) -> str: - """The callable's whole projected text: the graph keeps one text per callable, not the - module source the span would index into.""" - return self._code - - -def thread_code(unit: JCompilationUnit, code: Mapping[str, str]) -> None: - """Point every callable in ``unit`` at its projected text, keyed by node id. - - Runs after the unit is validated, because :meth:`JCompilationUnit.model_post_init` threads - itself onto every node it owns and would otherwise win. - """ - - def walk(t: JType) -> None: - for c in t.callables.values(): - c._unit = _ProjectedText(code.get(c.id, ""), unit.package) - for local in c.types.values(): - walk(local) - for nested in t.types.values(): - walk(nested) - - for top in unit.types.values(): - walk(top) - - # ---------------------------------------------------------------------------------------------- # leaves # ---------------------------------------------------------------------------------------------- -#: The model's own "not known". The graph stores ``start_line``/``end_line`` and nothing else, so -#: every column, every byte offset, and the whole span of a node it carries no lines for, are *not -#: projected* -- reported as this rather than as a ``0``, which would read as "column one, offset -#: zero" and index into a ``source`` that is ``""``. +#: The model's own "not known". The graph stores no column anywhere, and no byte offset on the +#: nodes listed in the module docstring -- reported as this rather than as a ``0``, which would read +#: as "column one, offset zero", a position and a wrong one. _UNKNOWN = -1 +def _byte_offsets(props: Props) -> Tuple[int, int]: + """``(start_byte, end_byte)`` -- the slice of the owning module's ``source`` this node's text is + -- or ``(-1, -1)`` when the projection carries no offsets for it. + + **Both or neither.** A half-known pair is the one shape that reads as data rather than as a gap: + ``(b0, -1)`` slices from ``b0`` to one byte before the end of the file, a wrong answer where + ``(-1, -1)`` is an empty one. + """ + b0, b1 = props.get("start_byte"), props.get("end_byte") + return (_UNKNOWN, _UNKNOWN) if b0 is None or b1 is None else (b0, b1) + + def span(props: Props) -> Optional[JSpan]: - """The line-only span the projection carries, or ``None`` when it carries no lines (an implicit - callable). Both columns and both byte offsets are :data:`_UNKNOWN`: the graph projects neither - (see the module docstring).""" + """The node's span, or ``None`` when the projection places it nowhere at all (an implicit + callable, which was never written). + + Lines are the graph's own; **columns are never projected** and stay :data:`_UNKNOWN`; byte + offsets come from ``start_byte``/``end_byte``, which codeanalyzer-java 3.2.0 writes on every + node whose text is a slice of its module's ``source``. Offsets without lines still make a span + -- that is the ``J_ANNOTATED_BY`` edge, which locates the annotation *application* the shared + ``:JAnnotation`` node cannot (see :func:`decorator`). + """ start, end = props.get("start_line"), props.get("end_line") - return None if start is None or end is None else JSpan(start=(start, _UNKNOWN), end=(end, _UNKNOWN), bytes=(_UNKNOWN, _UNKNOWN)) + offsets = _byte_offsets(props) + if start is None or end is None: + if offsets == (_UNKNOWN, _UNKNOWN): + return None + start = end = _UNKNOWN + return JSpan(start=(start, _UNKNOWN), end=(end, _UNKNOWN), bytes=offsets) + + +def body_span(props: Props) -> Optional[JSpan]: + """The callable's **body block**: ``body_start_byte`` opens it and the callable's own + ``end_byte`` closes it. + + ``None`` when either is absent -- an abstract or interface method has no body, an implicit + ``()`` was never written -- which is what makes :attr:`JCallable.code` fall back to the + declaration span, exactly as it does off ``analysis.json``. + + *The closing offset is measured, not assumed.* The projection carries no ``body_end_byte``, and + across both committed fixtures (``analysis_json/v2/{a1,a4}``, 1,182 callables carrying both + spans) there is **no callable** whose ``body_span.bytes[1]`` differs from its ``span.bytes[1]`` + -- a Java method declaration's last character *is* its body's closing brace. Lines: + ``body_start_line`` where the projection carries one, else :data:`_UNKNOWN`, and + :attr:`JCallable.code_start_line` falls back to the declaration's first line then; the end line + is the declaration's, which closes that same brace. + """ + b0, b1 = props.get("body_start_byte"), props.get("end_byte") + if b0 is None or b1 is None: + return None + return JSpan(start=(props.get("body_start_line", _UNKNOWN), _UNKNOWN), end=(props.get("end_line", _UNKNOWN), _UNKNOWN), bytes=(b0, b1)) def _unknown_span() -> JSpan: @@ -173,9 +180,14 @@ def docstring(props: Props) -> List[JComment]: def decorator(node: Props, edge: Props) -> JDecorator: - """An annotation use from its ``:JAnnotation`` node (keyed by name) and the ``J_ANNOTATED_BY`` - edge's ``arguments`` (the source spellings).""" - return JDecorator(name=node["name"], args=list(edge.get("arguments") or [])) + """An annotation use, from its ``:JAnnotation`` node (keyed by name) and the ``J_ANNOTATED_BY`` + edge's own properties: the ``arguments`` (the source spellings) and the application's position. + + The span rides the **edge** because the node cannot hold it: ``:JAnnotation`` is shared + vocabulary, deduped across every use site in the application, so it has no single position. The + edge carries the offsets and no lines, which is why :func:`span` builds a span from offsets + alone.""" + return JDecorator(name=node["name"], args=list(edge.get("arguments") or []), span=span(edge)) def field(props: Props, decorators: List[JDecorator]) -> JField: @@ -238,10 +250,9 @@ def body_node(props: Props, callee_signature: Optional[str]) -> JBodyNode: ``:JBodyNode`` at all; those figures are measured on the same analyzer's JSON, where the spans the key would have to agree with do exist.) """ - start, end = props.get("start_line"), props.get("end_line") return JBodyNode( kind=props["kind"], - span=None if start is None or end is None else JSpan(start=(start, _UNKNOWN), end=(end, _UNKNOWN), bytes=(_UNKNOWN, _UNKNOWN)), + span=span(props), callee=props.get("callee"), method_name=props.get("method_name"), receiver_expr=props.get("receiver_expr"), @@ -303,6 +314,7 @@ def callable_( is_entrypoint=bool(props.get("is_entrypoint", False)), entrypoint_frameworks=list(props.get("entrypoint_frameworks") or []), span=span(props), + body_span=body_span(props), ) @@ -337,14 +349,22 @@ def type_( def compilation_unit(props: Props, *, import_declarations: List[JImport], types: Dict[str, JType]) -> JCompilationUnit: + """The file, and with it the one text blob every node under it slices its own ``code`` out of + (:meth:`JCompilationUnit.slice`). + + ``source`` is read with ``.get`` -- **the deliberate exception** to this module's rule that every + non-boolean property the contract declares is read with ``props[...]``. A module the analyzer + could not read or could not decode carries no text, and that has to mean "no text for this whole + file", every node in it reporting ``""``, rather than an attach that raises over one file. + """ return JCompilationUnit( id=props["id"], package=props["package"], - source="", + source=props.get("source") or "", content_hash=props.get("content_hash"), imports=import_declarations, types=types, - span=_unknown_span(), + span=span(props) or _unknown_span(), ) diff --git a/cldk/models/java/models.py b/cldk/models/java/models.py index 240fe65f..9a25a166 100644 --- a/cldk/models/java/models.py +++ b/cldk/models/java/models.py @@ -83,10 +83,10 @@ class JSpan(_Base): sums over ``getBytes(UTF_8)``). **``-1`` in any position means "not known", never zero.** A span rebuilt from the Neo4j - projection carries real lines and ``-1`` for both columns and both byte offsets, because the - graph writes ``start_line``/``end_line`` and nothing else -- a ``0`` there would read as column - one, offset zero, which is a position, and a wrong one. Off ``analysis.json`` every position is - the analyzer's own. + projection carries real lines and real byte offsets -- codeanalyzer-java 3.2.0 writes both -- and + ``-1`` for both columns, which the graph does not write at all; a ``0`` there would read as + column one, which is a position, and a wrong one. Off ``analysis.json`` every position is the + analyzer's own. """ start: Tuple[int, int] @@ -455,12 +455,12 @@ def code(self) -> str: and ``TreesitterJava.get_calling_lines`` were written against; the declaration slice (``span``) only when there is no body (abstract / interface methods). - That holds for a callable read from ``analysis.json``. One read from the Neo4j projection - instead carries the whole **declaration** — the graph projects one line range per callable - and no ``body_span`` — so its ``code`` starts at ``public …`` and *ends with* what this - property would return. Likewise :attr:`body` there holds the ``call`` nodes only, about 30% - of the graph's body nodes, so :attr:`call_sites` is complete and nothing else about the - body is. + It holds on both backends: codeanalyzer-java 3.2.0 projects ``body_start_byte``, so a + callable rebuilt from the Neo4j graph slices the same body block out of the same + ``:JModule.source`` (before 3.2.0 it carried the whole declaration, which is the floor + ``JNeo4jBackend`` now refuses below). What still differs there is :attr:`body`, which holds + the ``call`` nodes only — about 30% of the graph's body nodes — so :attr:`call_sites` is + complete and nothing else about the body is. """ return self._slice(self.body_span or self.span) @@ -469,13 +469,14 @@ def code_start_line(self) -> int: """The file line :attr:`code` starts on: the body block's first line, or the declaration's when there is no body. - **It differs by backend wherever the opening brace does not sit on the declaration's first - line** — 398 of daytrader8's 1,216 callables. The Neo4j projection carries one line range - per callable and no ``body_span``, so this is the *declaration's* first line there and the - *body block's* here, exactly as :attr:`code` is the declaration there and the body block - here. The two agree on every callable whose ``{`` is on the signature's own line. + **The body span's own first line, when it is known.** Off ``analysis.json`` it always is. + The Neo4j projection carries the body block as byte offsets, so :attr:`code` is the body + block on both backends, but a ``body_start_line`` beside them is not guaranteed — where it is + absent this falls back to the declaration's first line, which is the body block's too except + where the opening brace sits on a later line (398 of daytrader8's 1,216 callables). ``-1`` + only when the callable has no span at all: an implicit ``()``, which has no text. """ - if self.body_span is not None: + if self.body_span is not None and self.body_span.start[0] != -1: return self.body_span.start[0] return self.start_line diff --git a/docs/agent-api-reference.md b/docs/agent-api-reference.md index 2ccfac31..1f6b0e0f 100644 --- a/docs/agent-api-reference.md +++ b/docs/agent-api-reference.md @@ -306,8 +306,8 @@ java = CLDK.java(backend=Neo4jConnectionConfig( application_name="daytrader8")) ``` -**Analyzer floor: codeanalyzer-java 3.1.1** (the pin is `[tool.backend-versions]` in -`pyproject.toml` and is ahead of the floor; `--emit neo4j` always runs at level 4 and +**Analyzer floor: codeanalyzer-java 3.2.0** (the pin is `[tool.backend-versions]` in +`pyproject.toml` and is equal to the floor; `--emit neo4j` always runs at level 4 and forces external calls). Attaching to a graph refuses rather than answering empty, and the message names what it found and the floor: @@ -315,15 +315,21 @@ names what it found and the floor: | --- | --- | | no `J_HAS_MODULE` / `J_HAS_METHOD` / `J_HAS_BODY_NODE` / `J_CALLS` (a pre-3.0.1 Java graph, a graph from another language's analyzer, an empty database) | refused — `GraphSchemaMismatch`, naming the missing types and the ones found | | no `:JApplication {id: can://}` | refused — that root is the anchor every statement walks out from, so a wrong application would make every answer empty | -| `analyzer_version` below 3.1.1, unreadable, or absent | refused | -| 3.1.1 and newer | served, silent | - -3.1.1 moved the application to the outermost segment of the `can://` grammar -(`can:///java//…`, was `can://java//…`) and made `@external` ids language-neutral -(`can:///@external/…`). A 3.1.0 graph has every relationship type and the right body-node -shape, and still answers every prefix-scoped statement with zero rows, so it is refused rather than -served. **Migration:** re-emit with `codeanalyzer-java>=3.1.1 --emit neo4j`, wiping the database -first — old and new ids do not collide. +| `analyzer_version` below 3.2.0, unreadable, or absent | refused | +| 3.2.0 and newer | served, silent | + +3.2.0 is the release whose projection carries the canonical text model: `:JModule.source` holds each +file whole, and a `start_byte`/`end_byte` pair reaches `:JType`, `:JField`, `:JVariable`, +`:JCallable` (plus `body_start_byte`) and `:JBodyNode`, so every node's text is a slice of its own +module. A 3.1.x graph carries text as `:JCallable.code` and no byte offsets at all, so on it every +*other* node's `code` rebuilds as `""` — served silently as though the file held nothing — which is +why it is refused rather than degraded. Two generations earlier, 3.1.1 moved the application to the +outermost segment of the `can://` grammar (`can:///java//…`, was `can://java//…`) and +made `@external` ids language-neutral (`can:///@external/…`); a 3.1.0 graph has every +relationship type and the right body-node shape and still answers every prefix-scoped statement with +zero rows. **Migration:** re-emit with `codeanalyzer-java>=3.2.0 --emit neo4j`. Wipe the database +first when the graph predates 3.1.1 — those ids do not collide with the current ones, so the two +generations would coexist rather than overwrite. Locally the same rule applies to the cache: an `analysis.json` with no `schema_version` (1.x output) is refused with a re-run message, not parsed into an empty application. @@ -343,14 +349,13 @@ last two from codeanalyzer-java 3.1.0; they raise on an older analysis rather th and issuing no new Cypher. Note what each one is: `get_imports()` is the project's **distinct sorted set** of import targets (the projection aggregates a module's imports per target, so file order is not recoverable); `get_variables()` is **local variables only**, keyed by the -`"."` call-graph key and ordered by `(line, name)` because `:JLocal` carries a -line-only span (fields are `get_fields`, parameters are `get_method_parameters`, and an unexpected +`"."` call-graph key and ordered by `(line, name)` because `:JLocal` carries no +column (fields are `get_fields`, parameters are `get_method_parameters`, and an unexpected keyword raises `TypeError` rather than being ignored); `get_class_hierarchy()` reads each declaration's own `base_types`/`interfaces` rather than `J_EXTENDS`/`J_IMPLEMENTS`, which is why library supertypes are in it — those two relationships join **8** of daytrader8's type pairs where the declarations join **103**; `get_methods_with_annotations()` keys by the spelling you passed and -its `body` is `JCallable.code`, so it is the body block in-process and the whole declaration over -the graph; `get_call_targets()` is simple-name matching with no overload resolution (use the call +its `body` is `JCallable.code`, the body block on either backend; `get_call_targets()` is simple-name matching with no overload resolution (use the call graph for what actually runs); `get_calling_lines()` is absolute **file** lines. **Three accessors still raise `NotImplementedError`** — `get_service_entry_point_classes` / `get_service_entry_point_methods`, which the **§4 erratum** in @@ -368,24 +373,26 @@ names its upstream issue where there is one: (`p.Outer.m(int).$anon$0`). External callees are not in this graph. - **CRUD accessors raise** (`codeanalyzer-java#187`): schema v2 carries no CRUD enrichment, and an empty list would read as "this application touches no database". -- **Over Neo4j, `JCallable.code` is the whole declaration**, not the body block (upstream - `codeanalyzer-java#176`), `code_start_line` is the declaration's first line rather than the body - block's (they differ on 398 of daytrader8's 1,216 callables), a module carries no `source` at all, - and every column and byte offset is `-1` — "not known", never zero. Line numbers are exact. The - one exception is a `JCallableParameter`, which round-trips out of `:JCallable.parameters_json` - with the analyzer's own columns *and* byte offsets; those offsets index a module `source` this - backend does not carry, so they locate the parameter in the file on disk and nothing else. -- **`get_source` inherits that difference, and so does `LocateResult.source`.** For a callable it is - the **body block** on the `analysis.json` backend and the whole **declaration** over Neo4j; the - relation is exact and total — the declaration *ends with* the body block — and asserted on all - 1,117 body-bearing callables of daytrader8 by the live suite, so either text can be relied on for - what it is. For a **body node** (the statement or call site `locate` returns in `node_id`) there - is text only on the `analysis.json` backend: `:JBodyNode` carries a line range and no text, and - there is no module `source` to slice one out of, so `get_source` raises over Neo4j and `describe` - leaves `source=None` — never the enclosing declaration standing in for it. A **module-scope** - `locate` over Neo4j is `source=""` plus a `module_source_unavailable` diagnostic. A - `resolve_value` ref (a `formal_in` vertex) has no text on either backend: it is a dataflow - position, not a region of the file. +- **Over Neo4j, every column is `-1`** — "not known", never zero. Line numbers and byte offsets + are exact: the projection writes `start_line`/`end_line` and a `start_byte`/`end_byte` pair, and + no column anywhere. A `JCallableParameter` is the one node whose columns are real, round-tripping + out of `:JCallable.parameters_json` with the analyzer's own span. +- **Text is the same on both backends since codeanalyzer-java 3.2.0.** `JCallable.code`, `get_source`, + `LocateResult.source` and `describe` all answer the same slice of the same file, at every + granularity: a callable's **body block**, a type's or field's or local's declaration, a single + statement or call site, and a module's whole text at module scope. Each is sliced out of + `:JModule.source` by the node's own byte offsets, so equality — not `endswith`, not "the same + length" — is what the live suite asserts, on all 1,117 body-bearing callables of daytrader8. + Before 3.2.0 the graph carried one line range per callable and text only as `:JCallable.code`, so + a callable came back as the whole **declaration** (which *ends with* the body block), + `code_start_line` was the declaration's first line rather than the body block's, a body node had + no text at all, and a module-scope `locate` was `""` plus a `module_source_unavailable` + diagnostic (upstream `codeanalyzer-java#176`). Three cases still have no text, on **both** + backends and for the same reason each time — nothing in the file to point at: an implicit + callable (a compiler-generated `()`), an `@external` callable, and a `resolve_value` ref (a + `formal_in` vertex is a dataflow position, not a region of the file). `module_source_unavailable` + survives as a *data* diagnostic: it fires on a module whose text the analyzer could not read or + decode, which on a 3.2.0 graph of daytrader8 is none of the 141. - **Over Neo4j, `cfg`/`cdg`/`ddg`/`summary` are `None` and `param_in`/`param_out` are empty at every level**, and re-ingesting will not change that: `--emit neo4j` already forces level 4, so the analyzer computed them — this leg simply does not project them back out (leg 3b reads the diff --git a/pyproject.toml b/pyproject.toml index dc5e92c5..801b4c3d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ dependencies = [ # The Neo4j-backed analysis backends (read-only; no analyzer is invoked). neo4j = ["neo4j>=5.14,<7"] # The local Java backend: the analyzer wheel carries the jar and a bundled JVM (jdk4py). -java = ["codeanalyzer-java==3.1.2"] +java = ["codeanalyzer-java==3.2.0"] # Everything. `codeanalyzer-python` and `codeanalyzer-typescript` are still hard # dependencies; #340 moves them here, and this list grows when it does. all = ["cldk[java]", "cldk[neo4j]"] @@ -86,7 +86,7 @@ include = [ ] [tool.backend-versions] -codeanalyzer-java = "3.1.2" +codeanalyzer-java = "3.2.0" codeanalyzer-python = "1.5.1" codeanalyzer-typescript = "1.5.3" diff --git a/tests/analysis/java/conftest.py b/tests/analysis/java/conftest.py index 7b6db63c..bb7bcad9 100644 --- a/tests/analysis/java/conftest.py +++ b/tests/analysis/java/conftest.py @@ -86,7 +86,7 @@ class FakeDriver: the ``:JApplication {id}`` anchor testable by behaviour rather than by grepping the statement.""" - def __init__(self, rel_types=V2_RELATIONSHIP_TYPES, responder=None, analyzer_version="3.1.1", application_name=None) -> None: + def __init__(self, rel_types=V2_RELATIONSHIP_TYPES, responder=None, analyzer_version="3.2.0", application_name=None) -> None: self.rel_types = set(rel_types) self.analyzer_version = analyzer_version self.application_name = application_name diff --git a/tests/analysis/java/test_java_addressing.py b/tests/analysis/java/test_java_addressing.py index 71a8ea6b..7a6ee756 100644 --- a/tests/analysis/java/test_java_addressing.py +++ b/tests/analysis/java/test_java_addressing.py @@ -82,8 +82,9 @@ def _local(payload: str) -> JCodeanalyzer: class _BodyNodeResponder: """The two statements the graph backend issues in the offline suites: the per-callable body-node fetch (leg 3b Task 1) and the port-lattice probe (Task 2). Both are answered out of the same - fixture, in the graph's own vocabulary (a global ``id``, ``kind``, a line-only span and the - ``J_RESOLVES_TO`` target's id as ``callee``), so the rows are shaped like the projection's + fixture, in the graph's own vocabulary (a global ``id``, ``kind``, the span's lines *and* byte + offsets -- codeanalyzer-java 3.2.0 projects both -- and the ``J_RESOLVES_TO`` target's id as + ``callee``), so the rows are shaped like the projection's rather than like the model's -- and the probe's answer is the fixture's own fact, not a constant: it is ``True`` exactly when some ``formal_in`` of the payload has an outgoing dependence edge, which is what the graph would report. @@ -105,7 +106,15 @@ def __init__(self, application: JApplication) -> None: def _walk(self, t) -> None: for c in t.callables.values(): self.rows[c.id] = [ - {"id": java_body_node_id(c.id, key), "kind": n.kind, "s": n.start_line if n.span else None, "e": n.end_line if n.span else None, "callee": n.callee} + { + "id": java_body_node_id(c.id, key), + "kind": n.kind, + "s": n.start_line if n.span else None, + "e": n.end_line if n.span else None, + "sb": n.span.bytes[0] if n.span else None, + "eb": n.span.bytes[1] if n.span else None, + "callee": n.callee, + } for key, n in c.body.items() ] for local in c.types.values(): @@ -402,18 +411,15 @@ def test_describe_accepts_a_locate_result(both): assert described[0].kind == found.body.kind -def test_a_body_node_hydrates_only_where_the_text_exists(analysis_json): - """The documented ``get_source`` divergence, on the finer grain: the local backend slices the - statement out of the module's real text; the graph carries none below callable granularity, so - the position is *found* and its source is ``None`` — never the enclosing declaration.""" +def test_a_body_node_hydrates_the_same_statement_on_both_backends(analysis_json): + """The ``get_source`` divergence that 3.2.0 closes, on the finest grain: the local backend slices + the statement out of the module's real text, and so does the graph now that the projection + carries the body node's own byte offsets. Not "the same length" or "contained in" — the same + string, because both are the same slice of the same file.""" local, graph = _local(analysis_json), _graph(analysis_json) found = next(r for line in range(600, 700) if (r := local.locate(TRADE_DIRECT_FILE, line)).body is not None) - assert local.describe([found])[0].source - assert graph.describe([found])[0].source is None - assert local.get_source(found.node_id) - with pytest.raises(KeyError) as e: - graph.get_source(found.node_id) - assert "no recoverable source" in str(e.value) + assert local.describe([found])[0].source == graph.describe([found])[0].source != None + assert local.get_source(found.node_id) == graph.get_source(found.node_id) def test_describe_answers_a_ref_resolve_value_just_minted(both): diff --git a/tests/analysis/java/test_java_addressing_live.py b/tests/analysis/java/test_java_addressing_live.py index 5c91f2b2..12de0572 100644 --- a/tests/analysis/java/test_java_addressing_live.py +++ b/tests/analysis/java/test_java_addressing_live.py @@ -32,17 +32,17 @@ CLDK_TEST_JAVA_CACHE=/path/to/dir \ # a level-4 reference analysis.json uv run pytest tests/analysis/java/test_java_addressing_live.py -**The two tolerances, each with its cause, both asserted rather than skipped:** - -* ``LocateResult.source`` and :meth:`get_source` on a callable are the **body block** locally and - the whole **declaration** over Neo4j, which *ends with* it (codeanalyzer-java#176: the graph - carries one line range per callable and no ``body_span``). Asserted as ``endswith``. -* Every column and byte offset is ``-1`` over Neo4j -- the projection writes ``start_line`` / - ``end_line`` and nothing else -- so spans are compared on their **lines**. - -A body node's *source* is not a tolerance but a documented absence: the graph carries no text below -callable granularity, so :meth:`describe` fills it locally and leaves it ``None`` over Neo4j, and -that is asserted too. +**The one tolerance, asserted rather than skipped:** every column is ``-1`` over Neo4j -- the +projection writes ``start_line`` / ``end_line`` and byte offsets, and no column anywhere -- so spans +are compared on their **lines**, and their byte offsets are compared for equality. + +**Text is no longer a tolerance.** codeanalyzer-java 3.2.0 projects ``:JModule.source`` plus a +``start_byte``/``end_byte`` pair down to the body nodes, so ``LocateResult.source``, +:meth:`get_source` and :meth:`describe` are asserted **equal** on both backends -- the same slice of +the same file, at every granularity including a single statement. Before 3.2.0 the graph carried one +line range per callable and no ``body_span``, this suite asserted ``endswith`` on a callable, and a +body node's source was ``None`` over Neo4j (codeanalyzer-java#176). That is the divergence the 3.2.0 +floor exists to have closed. Read-only, like every other Neo4j suite here. """ @@ -154,17 +154,20 @@ def test_locate_many_agrees_on_every_callable_and_every_module(backends): assert a.body is None or a.body.callee is None or a.body.callee == b.body.callee, where assert (a.span.start[0], a.span.end[0]) == (b.span.start[0], b.span.end[0]), where if a.callable is not None: - assert b.source.endswith(a.source), f"{where}: the graph's text is the declaration, which must end with the body block" + assert b.source == a.source, f"{where}: the two backends sliced different text out of the same file" with_body += a.body is not None assert with_body > 100, "no position landed on a body node; the comparison proved nothing about them" -def test_a_module_scope_result_says_the_graph_has_no_module_text(backends): +def test_a_module_scope_result_carries_the_module_text_on_both_backends(backends): + """``module_source_unavailable`` is a *data* diagnostic, not a backend one: it fires when the unit + carries no ``source``, which on a 3.2.0 graph is no unit at all (141/141 carry it). A graph that + lost a file's text would still say so here, and say it per module.""" ref, neo = backends path = next(iter(ref.get_symbol_table())) assert [d.code for d in ref.locate(path, 1).diagnostics] == ["module_scope"] - assert [d.code for d in neo.locate(path, 1).diagnostics] == ["module_scope", "module_source_unavailable"] - assert neo.locate(path, 1).source == "" and ref.locate(path, 1).source + assert [d.code for d in neo.locate(path, 1).diagnostics] == ["module_scope"] + assert neo.locate(path, 1).source == ref.locate(path, 1).source != "" def test_the_body_node_ids_are_the_ones_the_graph_carries(backends): @@ -275,18 +278,19 @@ def test_get_source_holds_the_documented_relation_on_every_callable(backends): for key, row in sorted(ref._addressing.by_key.items()): if row.callable.is_implicit: continue - assert neo.get_source(key).endswith(ref.get_source(key)), key + assert neo.get_source(key) == ref.get_source(key), key compared += 1 assert compared == 1117, compared -def test_describe_fills_a_callable_on_both_and_a_body_node_only_locally(backends): +def test_describe_fills_the_same_text_on_both_backends(backends): + """A callable and a single statement, both granularities: 3.2.0 puts byte offsets on the body + nodes too, so ``describe`` no longer answers ``None`` over Neo4j where it answers text locally.""" ref, neo = backends found = next(r for r in ref.locate_many(_positions(ref)) if r.body is not None) - assert ref.describe([found])[0].source - assert neo.describe([found])[0].source is None + assert neo.describe([found])[0].source == ref.describe([found])[0].source != None node = ref.resolve_callable(found.callable.signature, in_class=found.type.signature) - assert neo.describe([node])[0].source.endswith(ref.describe([node])[0].source) + assert neo.describe([node])[0].source == ref.describe([node])[0].source def test_has_resolution_edges_is_true_on_a_graph_emitted_the_documented_way(backends): diff --git a/tests/analysis/java/test_java_entrypoints_live.py b/tests/analysis/java/test_java_entrypoints_live.py index 07e57aaa..2b7b99f2 100644 --- a/tests/analysis/java/test_java_entrypoints_live.py +++ b/tests/analysis/java/test_java_entrypoints_live.py @@ -186,9 +186,9 @@ def test_method_bodies_and_call_sites_are_keyed_the_same_way(backends): ref, neo = backends keys = sorted(o.key for o in ref.get_callables_overview()) assert set(ref.get_method_bodies(keys)) == set(neo.get_method_bodies(keys)), "the two disagree about which callables have text" - # The text itself differs by backend exactly as ``get_source`` does (codeanalyzer-java#176): - # the graph's ``code`` is the whole declaration, which ends with the body block. - assert all(neo.get_method_bodies(keys)[k].endswith(ref.get_method_bodies(keys)[k]) for k in ref.get_method_bodies(keys)) + # The text is the same on both since 3.2.0: the same body block, sliced out of the same + # ``:JModule.source`` (it was the whole declaration over Neo4j -- codeanalyzer-java#176). + assert neo.get_method_bodies(keys) == ref.get_method_bodies(keys) a, b = ref.get_callsites_for(keys), neo.get_callsites_for(keys) assert set(a) == set(b) == set(keys) # Sorted, not in list order: the graph projects no **column** for a body node, so two calls on diff --git a/tests/analysis/java/test_java_neo4j_backend.py b/tests/analysis/java/test_java_neo4j_backend.py index b3f71391..46af282e 100644 --- a/tests/analysis/java/test_java_neo4j_backend.py +++ b/tests/analysis/java/test_java_neo4j_backend.py @@ -40,22 +40,26 @@ **The tolerances, each with its cause** (nothing here is a tolerance because it was inconvenient; see :mod:`cldk.analysis.java.neo4j.reconstruct` for the projection's side of each): -* ``JCompilationUnit.source`` is ``""`` — a module's text is not projected at all. -* ``JCallable.code`` is the whole **declaration**, the local backend's is the **body block**: the - projection carries one line range per callable, the declaration's, and no ``body_span``. The - relation is exact and total, so it is asserted rather than skipped: - ``neo.code.endswith(ref.code)``. ``code_start_line`` therefore agrees except where the opening - brace sits below the declaration's first line. ``calling_lines`` used to shift by that same - prefix and no longer do: they are absolute file lines, which both backends can spell, so they - are asserted equal on every edge rather than tolerated. +* **Text is not a tolerance any more.** codeanalyzer-java 3.2.0 projects the whole file as + ``:JModule.source`` and a ``start_byte``/``end_byte`` pair on the nodes under it, so + ``JCompilationUnit.source`` and every ``code`` are asserted **equal**, not related: both sides are + the same slice of the same file. Before 3.2.0 ``JCallable.code`` was the whole declaration against + the local backend's body block and this suite asserted ``neo.code.endswith(ref.code)`` + (codeanalyzer-java#176); that is the divergence the 3.2.0 floor exists to have closed. + ``calling_lines`` are absolute file lines, which both backends can spell, so they are asserted + equal on every edge. +* ``JCompilationUnit.comments`` is ``[]``: comment *nodes* are still not projected, so a unit's own + comment list is empty even though the text they were cut from is now present. A type's and a + callable's javadoc rides its own property and is asserted. * Order within one source line is not recoverable: a field, a local variable and a call site carry a line but no column in the graph, so a declaration's ``field_declarations`` and ``local_variables`` are compared as multisets. Annotation order is not recoverable at all - (``J_ANNOTATED_BY`` carries only ``arguments``), so ``annotations`` is compared as a multiset. -* **Every column and every byte offset is ``-1``** on every node, not ``0``: the projection writes - ``start_line``/``end_line`` and nothing else, so a position within a line and an offset into a - ``source`` the graph does not carry are *not known*. The sentinel is asserted, not skipped, on - types, callables, fields and call sites — a ``0`` would read as column one, offset zero. + (``J_ANNOTATED_BY`` carries ``arguments`` and the application's own byte offsets, not an index), + so ``annotations`` is compared as a multiset. +* **Every column is ``-1``** on every node, not ``0``: the projection writes ``start_line``/ + ``end_line`` and byte offsets and no column anywhere, so a position *within* a line is not known. + The sentinel is asserted, not skipped, on types, callables, fields and call sites — a ``0`` would + read as column one. Byte offsets are the opposite case and are asserted equal. * ``imports`` are aggregated per import target, so a file's import order is not recoverable; the set is. * ``get_all_docstrings`` reports the javadoc of each file's *declarations* — type, callable, field, @@ -159,7 +163,8 @@ def test_symbol_table_parity(backends): other = st_n[key] assert (other.file_path, other.package, other.content_hash) == (unit.file_path, unit.package, unit.content_hash) assert sorted(other.imports) == sorted(unit.imports), f"{key}: import set differs" - assert other.source == "" and other.comments == [] # documented: not projected + assert other.source == unit.source, f"{key}: the module text is the same file on both backends" + assert other.comments == [] # documented: comment nodes are not projected def test_application_view_parity(backends): @@ -194,7 +199,8 @@ def test_type_parity(backends): assert (o.is_entrypoint_class, o.qualified_name, o.parent_type, o.name) == (t.is_entrypoint_class, t.qualified_name, t.parent_type, t.name), name assert (o.start_line, o.end_line) == (t.start_line, t.end_line), name assert (o.start_column, o.end_column) == (-1, -1), f"{name}: a column the graph does not carry must be -1, not 0" - assert o.span.bytes == (-1, -1), f"{name}: a byte offset into a source the graph does not carry must be -1, not 0" + assert o.span.bytes == t.span.bytes, f"{name}: the byte offsets differ, so the two backends are not slicing the same text" + assert o.code == t.code, f"{name}: the declaration text differs" assert _annotations(o) == _annotations(t), name assert sorted(o.fields) == sorted(t.fields) and sorted(o.callables) == sorted(t.callables) and sorted(o.types) == sorted(t.types), name assert sorted(o.nested_type_declarations) == sorted(t.nested_type_declarations), name @@ -210,7 +216,8 @@ def test_field_parity(backends): assert [f.name for f in fr] == [f.name for f in fn], name for a, b in zip(fr, fn): assert (b.id, b.type, b.modifiers, b.initializer, b.start_line, b.end_line) == (a.id, a.type, a.modifiers, a.initializer, a.start_line, a.end_line), f"{name}.{a.name}" - assert (b.start_column, b.end_column) == (-1, -1) and b.span.bytes == (-1, -1), f"{name}.{a.name}: columns and byte offsets are not projected" + assert (b.start_column, b.end_column) == (-1, -1), f"{name}.{a.name}: columns are not projected" + assert (b.span.bytes, b.code) == (a.span.bytes, a.code), f"{name}.{a.name}: the field text differs" assert _annotations(b) == _annotations(a), f"{name}.{a.name}" assert b.variables == a.variables and b.variable_initializers == a.variable_initializers @@ -228,7 +235,8 @@ def test_callable_parity(backends): assert (o.is_implicit, o.is_entrypoint, o.is_constructor, o.is_static) == (m.is_implicit, m.is_entrypoint, m.is_constructor, m.is_static), where assert (o.start_line, o.end_line) == (m.start_line, m.end_line), where if o.span is not None: # absent on the implicit callables, on both backends - assert (o.start_column, o.end_column) == (-1, -1) and o.span.bytes == (-1, -1), f"{where}: columns and byte offsets are not projected" + assert (o.start_column, o.end_column) == (-1, -1), f"{where}: columns are not projected" + assert o.span.bytes == m.span.bytes, f"{where}: the declaration's byte offsets differ" assert o.thrown_exceptions == m.thrown_exceptions and o.cyclomatic_complexity == m.cyclomatic_complexity, where assert sorted(o.referenced_types) == sorted(m.referenced_types) and sorted(o.accessed_fields) == sorted(m.accessed_fields), where assert (o.refs is None) == (m.refs is None), where @@ -238,11 +246,10 @@ def test_callable_parity(backends): # Local variables: same multiset; within-line order is not recoverable. key = lambda v: (v.name, v.type, v.initializer, v.start_line) assert sorted(map(key, o.variable_declarations)) == sorted(map(key, m.variable_declarations)), where - # ``code``: identical without a body, otherwise the body block behind its declaration. - if m.code: - assert o.code.endswith(m.code), where - else: - assert o.code == "", where + # ``code``: the same body block, sliced out of the same ``:JModule.source``. Equality is + # what 3.2.0 buys -- ``endswith`` was the pre-3.2.0 relation (codeanalyzer-java#176). + assert o.code == m.code, where + assert o.code_start_line == m.code_start_line, where def test_parameter_parity(backends): diff --git a/tests/analysis/java/test_java_neo4j_multi_application_scope.py b/tests/analysis/java/test_java_neo4j_multi_application_scope.py index 9adb6438..371e805e 100644 --- a/tests/analysis/java/test_java_neo4j_multi_application_scope.py +++ b/tests/analysis/java/test_java_neo4j_multi_application_scope.py @@ -81,21 +81,61 @@ def edge(self, src: str, rel: str, dst: str, **props: Any) -> None: _PARAMS_JSON = '[{"name":"%s","type":"java.lang.String","modifiers":[],"decorators":[],"is_variadic":false}]' +#: The two files the fixture graph projects, one ``:JModule.source`` each (codeanalyzer-java 3.2.0). +#: Every byte offset below is *derived* from these by :func:`_bytes`, and every ``start_line`` matches +#: the line the text is really on -- a fixture whose offsets were counted by hand would pin the +#: arithmetic to itself rather than to the file. +_WIDGET_SOURCE = """package shared; + +public class Widget { + private int %(tag)s_attr; + + public String render(String %(tag)s) { + int %(tag)s_var = 1; return helper(); + } + + static class Inner { + void ping() { + } + } +} +""" + +_HELPER_SOURCE = """package shared; + +class Helper { + static String help() { + return "%(tag)s help"; + } +} +""" + + +def _bytes(src: str, text: str, through: str = "") -> Tuple[int, int]: + """``(start_byte, end_byte)`` of ``text`` in ``src``, extended to the end of the first ``through`` + after it. Both files are ASCII, so a character index *is* a UTF-8 byte offset here.""" + b0 = src.index(text) + return b0, (src.index(through, b0 + len(text)) + len(through) if through else b0 + len(text)) + def _build() -> _Graph: g = _Graph() g.node("Named", ["JAnnotation"], name="Named") g.node("java.util", ["JPackage"], name="java.util") for app, tag in ((APP_A, "alpha"), (APP_B, "beta")): - app_id = g.node(f"can://{app}", ["JApplication"], name=app, schema_version="2.0.0", analyzer_name="codeanalyzer-java", analyzer_version="3.1.1") - # Both applications declare the same two repo-relative paths -- the key collision. - mod = g.node(f"can://{app}/java/{SHARED_MODULE}", ["JModule"], file_key=SHARED_MODULE, package="shared", content_hash=f"{tag}hash") + app_id = g.node(f"can://{app}", ["JApplication"], name=app, schema_version="2.0.0", analyzer_name="codeanalyzer-java", analyzer_version="3.2.0") + widget_src, helper_src = _WIDGET_SOURCE % {"tag": tag}, _HELPER_SOURCE % {"tag": tag} + # Both applications declare the same two repo-relative paths -- the key collision. The two + # ``source`` blobs are what every slice below is taken out of, so a leak reads as the other + # application's identifier inside the text, not merely as a wrong count. + mod = g.node(f"can://{app}/java/{SHARED_MODULE}", ["JModule"], file_key=SHARED_MODULE, package="shared", content_hash=f"{tag}hash", source=widget_src) g.edge(app_id, "J_HAS_MODULE", mod) g.edge(mod, "J_IMPORTS", "java.util", spellings=[f"java.util.{tag.title()}List"], is_static=None) - helper_mod = g.node(f"can://{app}/java/{OTHER_MODULE}", ["JModule"], file_key=OTHER_MODULE, package="shared", content_hash=f"{tag}helper") + helper_mod = g.node(f"can://{app}/java/{OTHER_MODULE}", ["JModule"], file_key=OTHER_MODULE, package="shared", content_hash=f"{tag}helper", source=helper_src) g.edge(app_id, "J_HAS_MODULE", helper_mod) # shared.Widget in both applications, same qualified name, different members. + cls_bytes = _bytes(widget_src, "public class Widget", "\n}") cls = g.node( f"{mod}/Widget", ["JSymbol", "JType"], @@ -106,10 +146,17 @@ def _build() -> _Graph: interfaces=["shared.Face"], docstring=f"{tag} class doc", start_line=3, - end_line=40, + end_line=14, + start_byte=cls_bytes[0], + end_byte=cls_bytes[1], ) g.edge(mod, "J_DECLARES", cls) g.edge(cls, "J_ANNOTATED_BY", "Named", arguments=[f'"{tag}"']) + # ``code`` is still projected (3.2.0 retains it) and is the whole *declaration*; nothing in + # the SDK reads it any more, and the body-block assertions below go red if anything starts. + decl_bytes = _bytes(widget_src, f"public String render(String {tag})", "\n }") + body_bytes = _bytes(widget_src, "{\n int", "\n }") + assert body_bytes[1] == decl_bytes[1], "a Java declaration's last character is its body's closing brace" method = g.node( f"{cls}/{METHOD_SIG}", ["JSymbol", "JCallable"], @@ -120,22 +167,40 @@ def _build() -> _Graph: return_type="java.lang.String", parameters_json=_PARAMS_JSON % tag, modifiers=["public"], - code=f"public String render(String {tag}) {{ return helper(); }}", + code=widget_src[decl_bytes[0] : decl_bytes[1]], docstring=f"{tag} method doc", cyclomatic_complexity=1, referenced_types=[f"shared.{tag.title()}"], accessed_fields=[f"shared.Widget.{tag}_attr"], start_line=6, end_line=8, + start_byte=decl_bytes[0], + end_byte=decl_bytes[1], + body_start_byte=body_bytes[0], ) g.edge(cls, "J_HAS_METHOD", method) ctor = g.node(f"{cls}/()", ["JSymbol", "JCallable"], name="", signature="()", kind="constructor", is_implicit=True) g.edge(cls, "J_HAS_METHOD", ctor) - field = g.node(f"{cls}#field#{tag}_attr", ["JField"], name=f"{tag}_attr", type="int", modifiers=["private"], start_line=4, end_line=4) + field_bytes = _bytes(widget_src, f"private int {tag}_attr;") + field = g.node(f"{cls}#field#{tag}_attr", ["JField"], name=f"{tag}_attr", type="int", modifiers=["private"], start_line=4, end_line=4, start_byte=field_bytes[0], end_byte=field_bytes[1]) g.edge(cls, "J_HAS_FIELD", field) - nested = g.node(f"{cls}/Inner", ["JSymbol", "JType"], name="Inner", kind="class", modifiers=["static"], start_line=20, end_line=30) + nested_bytes = _bytes(widget_src, "static class Inner {", "\n }") + nested = g.node(f"{cls}/Inner", ["JSymbol", "JType"], name="Inner", kind="class", modifiers=["static"], start_line=10, end_line=13, start_byte=nested_bytes[0], end_byte=nested_bytes[1]) g.edge(cls, "J_DECLARES", nested) - nested_m = g.node(f"{nested}/ping()", ["JSymbol", "JCallable"], name="ping", signature="ping()", kind="method", code=f"{tag} inner code", start_line=21, end_line=22) + ping_bytes = _bytes(widget_src, "void ping() {", "\n }") + nested_m = g.node( + f"{nested}/ping()", + ["JSymbol", "JCallable"], + name="ping", + signature="ping()", + kind="method", + code=widget_src[ping_bytes[0] : ping_bytes[1]], + start_line=11, + end_line=12, + start_byte=ping_bytes[0], + end_byte=ping_bytes[1], + body_start_byte=_bytes(widget_src, "{\n }")[0], + ) g.edge(nested, "J_HAS_METHOD", nested_m) local = g.node(f"{method}/$anon$0", ["JSymbol", "JType"], name="$anon$0", kind="class", start_line=7, end_line=7) g.edge(method, "J_DECLARES", local) @@ -143,14 +208,30 @@ def _build() -> _Graph: # callable, so this collides with the one above unless the callable is part of the key. ctor_local = g.node(f"{ctor}/$anon$0", ["JSymbol", "JType"], name="$anon$0", kind="class", start_line=5, end_line=5) g.edge(ctor, "J_DECLARES", ctor_local) - var = g.node(f"{method}#{tag}_var@7", ["JVariable"], name=f"{tag}_var", type="int", initializer="1", start_line=7, end_line=7) + var_bytes = _bytes(widget_src, f"int {tag}_var = 1;") + var = g.node(f"{method}#{tag}_var@7", ["JVariable"], name=f"{tag}_var", type="int", initializer="1", start_line=7, end_line=7, start_byte=var_bytes[0], end_byte=var_bytes[1]) g.edge(method, "J_DECLARES_VAR", var) # A helper the method calls, in the other module, plus one external target. - helper_cls = g.node(f"{helper_mod}/Helper", ["JSymbol", "JType"], name="Helper", kind="class", start_line=1, end_line=9) + helper_cls_bytes = _bytes(helper_src, "class Helper {", "\n}") + helper_cls = g.node(f"{helper_mod}/Helper", ["JSymbol", "JType"], name="Helper", kind="class", start_line=3, end_line=7, start_byte=helper_cls_bytes[0], end_byte=helper_cls_bytes[1]) g.edge(helper_mod, "J_DECLARES", helper_cls) - helper = g.node(f"{helper_cls}/help()", ["JSymbol", "JCallable"], name="help", signature="help()", kind="method", code=f"{tag} help", start_line=2, end_line=3) + help_bytes = _bytes(helper_src, "static String help()", "\n }") + helper = g.node( + f"{helper_cls}/help()", + ["JSymbol", "JCallable"], + name="help", + signature="help()", + kind="method", + code=helper_src[help_bytes[0] : help_bytes[1]], + start_line=4, + end_line=6, + start_byte=help_bytes[0], + end_byte=help_bytes[1], + body_start_byte=_bytes(helper_src, "{\n return")[0], + ) g.edge(helper_cls, "J_HAS_METHOD", helper) + call_bytes = _bytes(widget_src, "helper();") call = g.node( f"{method}@7:12", ["JBodyNode"], @@ -165,6 +246,8 @@ def _build() -> _Graph: argument_expr=[], start_line=7, end_line=7, + start_byte=call_bytes[0], + end_byte=call_bytes[1], ) g.edge(method, "J_HAS_BODY_NODE", call) g.edge(call, "J_RESOLVES_TO", helper) @@ -440,7 +523,7 @@ def _backend() -> JNeo4jBackend: # ===================================================================================== -# The fake graph is what a 3.1.1 graph is +# The fake graph is what a 3.2.0 graph is # ===================================================================================== def test_the_fake_graph_carries_no_module_property_and_no_v1_vocabulary(): assert GRAPH.nodes and not any("_module" in props for _, props in GRAPH.nodes.values()) @@ -497,8 +580,9 @@ def test_get_all_classes_covers_nested_and_local_types_of_this_application_only( def test_get_method_and_parameters_resolve_inside_the_application_only(): backend = _backend() method = backend.get_method(CLASS_FQN, METHOD_SIG) - assert method is not None and method.code.endswith("return helper(); }") + assert method is not None and method.code == "{\n int alpha_var = 1; return helper();\n }", "code is the body block, sliced out of :JModule.source" assert "alpha" in method.code and "beta" not in method.code + assert method.code_start_line == 6 and method.start_line == 6 assert [p.name for p in backend.get_method_parameters(CLASS_FQN, METHOD_SIG)] == ["alpha"] assert backend.get_method(CLASS_FQN, "noSuchMethod()") is None assert backend.get_all_methods_in_class(CLASS_FQN) == {METHOD_SIG: method} @@ -516,7 +600,7 @@ def test_call_graph_keys_by_fqn_and_signature_and_drops_externals(): graph = _backend().get_call_graph() assert set(graph.edges) == {(f"{CLASS_FQN}.{METHOD_SIG}", "shared.Helper.help()")} assert all("can://" not in n for n in graph.nodes) - assert graph.nodes[f"{CLASS_FQN}.{METHOD_SIG}"]["method_detail"].method.code.startswith("public String render(String alpha)") + assert "alpha_var" in graph.nodes[f"{CLASS_FQN}.{METHOD_SIG}"]["method_detail"].method.code, "the call-graph node's text came from application B" edge = graph.edges[f"{CLASS_FQN}.{METHOD_SIG}", "shared.Helper.help()"] assert edge["type"] == "CALL_DEP" and edge["weight"] == 1 @@ -565,9 +649,10 @@ def test_the_addressing_surface_answers_from_this_application_only(): assert node.ref.startswith(f"can://{APP_A}/") assert "alpha" in backend.get_source(node.callable) assert backend.resolve_value("alpha", within="Widget.render").ref == f"{node.ref}@formal_in:0" - # The graph carries no text below callable granularity: the position is found, its source is - # ``None`` -- never application B's, and never the enclosing declaration standing in for it. - assert backend.describe([found])[0].source is None + # Text reaches below callable granularity since 3.2.0: the body node carries its own offsets, so + # its source is its own slice -- never application B's, and never the enclosing declaration + # standing in for it. A body node the projection places nowhere still describes as ``None``. + assert backend.describe([found])[0].source == "helper();" def test_the_task_three_surface_answers_from_this_application_only(): @@ -583,7 +668,7 @@ def test_the_task_three_surface_answers_from_this_application_only(): "shared.Widget.Inner.ping()", "shared.Helper.help()", }, "the projection is the addressing domain of *this* application" - assert backend.get_method_bodies(list(keys))[f"{CLASS_FQN}.{METHOD_SIG}"].endswith("return helper(); }") + assert backend.get_method_bodies(list(keys))[f"{CLASS_FQN}.{METHOD_SIG}"].endswith("return helper();\n }") assert "beta" not in "".join(backend.get_method_bodies(list(keys)).values()) assert [s.method_name for s in backend.get_callsites_for([f"{CLASS_FQN}.{METHOD_SIG}"])[f"{CLASS_FQN}.{METHOD_SIG}"]] == ["help"] assert [o.key for o in backend.get_decorated_callables(["Named"])] == [], "the annotation is on the type, not the callable" diff --git a/tests/analysis/java/test_java_neo4j_scale.py b/tests/analysis/java/test_java_neo4j_scale.py index b5ec99aa..6c48e324 100644 --- a/tests/analysis/java/test_java_neo4j_scale.py +++ b/tests/analysis/java/test_java_neo4j_scale.py @@ -135,10 +135,12 @@ def test_get_test_methods_answers_off_the_graph(backend): """The accessor daytrader8 cannot exercise at all: it ships zero ``@Test`` methods, so ``{}`` there is correct whatever the implementation does. ThingsBoard carries thousands. - The 1.x implementation re-parsed each ``JCompilationUnit.source`` with Tree-sitter, and this - projection carries no module source (``source=""`` on every unit), so it returned ``{}`` here — - an empty reading as "this application has no tests" on an application with 3,354 annotated - callables. The annotations are in the graph on ``J_ANNOTATED_BY``, which is what is read now. + The 1.x implementation re-parsed each ``JCompilationUnit.source`` with Tree-sitter, which + returned ``{}`` on any projection that carried no module source — an empty reading as "this + application has no tests" on an application with 3,354 annotated callables. The annotations are + in the graph on ``J_ANNOTATED_BY``, which is what is read now. Since codeanalyzer-java 3.2.0 the + projection does carry ``:JModule.source``, but that is text for slicing, not a parse target: this + accessor still reads the edge, so it cannot regress to re-parsing a file that may be absent. """ from cldk.analysis.java.java_analysis import _TEST_ANNOTATIONS diff --git a/tests/analysis/java/test_java_schema_probe.py b/tests/analysis/java/test_java_schema_probe.py index 7a86d27a..2753cd12 100644 --- a/tests/analysis/java/test_java_schema_probe.py +++ b/tests/analysis/java/test_java_schema_probe.py @@ -83,20 +83,23 @@ def test_probe_refuses_a_python_graph_naming_the_missing_java_types(fake_driver) assert "PY_CALLS" in str(e.value) -@pytest.mark.parametrize("raw", ["3.0.0", "3.0.1", "3.0.2", "3.0.3", "3.1.0"]) +@pytest.mark.parametrize("raw", ["3.0.0", "3.0.1", "3.0.2", "3.0.3", "3.1.0", "3.1.1", "3.1.2"]) def test_probe_refuses_a_graph_below_the_analyzer_floor(fake_driver, raw): - """Every generation below 3.1.1 is refused, naming the version found and the floor. + """Every generation below 3.2.0 is refused, naming the version found and the floor. - Two of these are the ones that matter, and both declare every relationship type the fingerprint + Three of these are the ones that matter, and all declare every relationship type the fingerprint asks for, so the fingerprint passes and the version stamp is the only signal: * ``3.0.0`` -- the vocabulary is there but it stamped contract 2.2.0 with a different body-node - id grammar (J-9, the reason 3.0.1 was the floor). - * ``3.1.0`` -- **the release immediately below the floor**, and the one the floor exists for. - Its ids are ``can://java//…``: the application prefix every statement here scopes on - matches none of them, so it attaches cleanly and answers everything with zero rows.""" + id grammar (J-9, the reason 3.0.1 was the first floor). + * ``3.1.0`` -- ids are ``can://java//…``, so the application prefix every statement here + scopes on matches none of them: it would attach cleanly and answer everything with zero rows. + That is what the 3.1.1 floor existed for. + * ``3.1.2`` -- **the release immediately below the floor**, and the one this floor exists for. It + projects text as ``:JCallable.code`` and no byte offsets at all, so every other node's ``code`` + would rebuild as ``""`` -- served, silently, as though the file held nothing.""" fake_driver.analyzer_version = raw - with pytest.raises(GraphSchemaMismatch, match=rf"{raw}.*3\.1\.1 or newer"): + with pytest.raises(GraphSchemaMismatch, match=rf"{raw}.*3\.2\.0 or newer"): JNeo4jBackend._from_driver(fake_driver, application_name="daytrader8") @@ -114,15 +117,15 @@ def test_probe_refuses_when_the_version_cannot_be_read(fake_driver, raw, found): because serving it would be the silent-empty defect with no signal -- and the message says which of the three it found.""" fake_driver.analyzer_version = raw - with pytest.raises(GraphSchemaMismatch, match="3.1.1 or newer") as e: + with pytest.raises(GraphSchemaMismatch, match="3.2.0 or newer") as e: JNeo4jBackend._from_driver(fake_driver, application_name="daytrader9") assert found in str(e.value) -@pytest.mark.parametrize("raw", ["3.1.1", "3.1.2", "3.2.0", "4.0.0"]) +@pytest.mark.parametrize("raw", ["3.2.0", "3.2.1", "3.3.0", "4.0.0"]) def test_probe_serves_every_generation_from_the_floor_up_silently(fake_driver, caplog, raw): - """The other direction of the floor: 3.1.1 -- the release that put the application outermost -- - is served, and so is anything above it.""" + """The other direction of the floor: 3.2.0 -- the release whose projection carries the canonical + text model -- is served, and so is anything above it.""" fake_driver.analyzer_version = raw with caplog.at_level(logging.INFO, logger="cldk.analysis.java.neo4j.neo4j_backend"): backend = JNeo4jBackend._from_driver(fake_driver, application_name="daytrader8") diff --git a/tests/analysis/java/test_java_v1_accessors_live.py b/tests/analysis/java/test_java_v1_accessors_live.py index edf8dcae..ec89d1f4 100644 --- a/tests/analysis/java/test_java_v1_accessors_live.py +++ b/tests/analysis/java/test_java_v1_accessors_live.py @@ -159,14 +159,18 @@ def test_the_import_set_is_smaller_than_the_per_file_declarations(backends): # ---- get_variables ---------------------------------------------------------------------------- def test_the_local_variables_agree_name_type_and_line(backends): - """``J_DECLARES_VAR`` carries a **line-only** span, so the columns and byte offsets are - placeholders over the graph exactly as they are everywhere else on this surface; everything - that is a fact about the variable agrees.""" + """``:JVariable`` carries no column, so those stay placeholders over the graph exactly as they + are everywhere else on this surface; its **byte offsets** are real since codeanalyzer-java 3.2.0 + (863 of daytrader8's 863 locals carry them) and are asserted equal. ``JLocalVariable.code`` + raises on **both** backends and is not asserted: ``_thread_type`` threads a type's fields, + callables and body nodes into the compilation unit and not a callable's locals, so neither side + has a unit to slice -- the same answer from the same model, not a projection gap.""" ref, neo = backends local, graph = ref.get_variables(), neo.get_variables() assert set(local) == set(graph) and len(local) == DT_CALLABLES for key, declared in local.items(): assert [(v.name, v.type, v.start_line, v.initializer) for v in declared] == [(v.name, v.type, v.start_line, v.initializer) for v in graph[key]], key + assert [v.span.bytes for v in declared] == [v.span.bytes for v in graph[key]], f"{key}: the two backends place the same local at different bytes" assert sum(1 for v in local.values() if v) == DT_DECLARING_LOCALS assert sum(len(v) for v in local.values()) == DT_LOCALS @@ -255,8 +259,9 @@ def test_the_call_targets_agree(backends): # ---- get_calling_lines -------------------------------------------------------------------------- def test_the_calling_lines_agree_and_are_absolute_file_lines(backends): """Leg 3a made these agree rather than shift by a declaration prefix; this is the assertion - that keeps them agreeing over a real projection, where ``code`` and ``code_start_line`` really - do differ between the two backends.""" + that keeps them agreeing over a real projection. It was written when ``code`` and + ``code_start_line`` still differed between the two backends, which is what made the shift + possible; 3.2.0 makes both equal, and these lines are absolute file lines either way.""" ref, neo = backends lines = ref.get_calling_lines("getStatement") assert lines == neo.get_calling_lines("getStatement") diff --git a/uv.lock b/uv.lock index ea97651c..4f0ea175 100644 --- a/uv.lock +++ b/uv.lock @@ -350,7 +350,7 @@ test = [ requires-dist = [ { name = "cldk", extras = ["java"], marker = "extra == 'all'" }, { name = "cldk", extras = ["neo4j"], marker = "extra == 'all'" }, - { name = "codeanalyzer-java", marker = "extra == 'java'", specifier = "==3.1.2" }, + { name = "codeanalyzer-java", marker = "extra == 'java'", specifier = "==3.2.0" }, { name = "codeanalyzer-python", specifier = "==1.5.1" }, { name = "codeanalyzer-typescript", specifier = "==1.5.3" }, { name = "neo4j", marker = "extra == 'neo4j'", specifier = ">=5.14,<7" }, @@ -398,13 +398,13 @@ wheels = [ [[package]] name = "codeanalyzer-java" -version = "3.1.2" +version = "3.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jdk4py" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/aa/def8074c19b85c7d644c936eefa2f6be1a14f4f5ae06acc059c29405cd7d/codeanalyzer_java-3.1.2-py3-none-any.whl", hash = "sha256:77d9d894c8a225cc38a1217876cc42ca7abfcbd3c2ab10abecbbc338f5ac0872", size = 32839694, upload-time = "2026-09-09T14:07:37.058Z" }, + { url = "https://files.pythonhosted.org/packages/c5/06/26d6c653ada36ce11358b08a33bbc24ca8b6f0da8b843c379c6d160691a3/codeanalyzer_java-3.2.0-py3-none-any.whl", hash = "sha256:c4e98c22c719bdb1665e98d8bcee4e2d81cc18ec518f66e467d77bdd6d871251", size = 32840590, upload-time = "2026-09-10T15:14:49.099Z" }, ] [[package]] From a12e059fc396a7bb12357af74fd46d3b93fc007c Mon Sep 17 00:00:00 2001 From: Rahul Krishna Date: Thu, 10 Sep 2026 18:30:33 -0400 Subject: [PATCH 4/7] chore(deps): move the sibling analyzer pins to codeanalyzer-python 1.5.2 and codeanalyzer-typescript 1.6.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both releases are Neo4j-projection-only conformance fixes — the divergence codeanalyzer-java 3.2.0 closed for Java, closed for the siblings. python 1.5.2 adds :PyModule.source, all six span properties wherever a span is declared, :PyVariable.value_json, :PyBodyNode.callee_signature, PY_IMPORTS.positions_json and a span on PY_DECORATED_BY; typescript 1.6.0 adds :TSModule.source and the four new span properties across ten labels. Neither touches analysis.json, and the TypeScript fixtures prove it: regenerated with the 1.6.0 wheel at all four levels, they are byte-identical to the 1.5.3 generation apart from the analyzer.version stamp, compared by parsing both and masking that one field. Neither Neo4j floor moves — 1.5.0 for Python, 1.5.2 for TypeScript. Raising a floor is what would let the SDK read the new text, and that is uptake work the size of #394, tracked in #396 (Python) and #391 (TypeScript). The pin is what the SDK installs; the floor is what it requires of a graph. The prose those releases make false is corrected rather than deleted: every place that said "the graph does not carry this" now says the SDK does not read it, and names the issue that will. That covers the TypeScript lossiness rows and the cross-language locate gotcha in docs/agent-api-reference.md (which claimed :PyModule nodes "genuinely do not store source text"), the module_source_unavailable row in the diagnostics table, four module docstrings, callsite()'s claim that columns are not projected, CLAUDE.md's TypeScript row, and the fixtures README. One improvement is free on a re-emitted Python graph: reconstruct.callsite reads start_column with a -1 default, so 1.5.2 supplies real columns and an older graph still answers -1 — no version branch. Gate: 1601 passed, 370 skipped, coverage 85.11%, run solo on this commit. Closes #397. --- CLAUDE.md | 2 +- cldk/analysis/python/neo4j/neo4j_backend.py | 8 ++++-- cldk/analysis/python/neo4j/reconstruct.py | 28 +++++++++++++------ .../typescript/neo4j/neo4j_backend.py | 3 +- cldk/analysis/typescript/neo4j/reconstruct.py | 11 ++++++-- docs/agent-api-reference.md | 25 ++++++++++------- pyproject.toml | 8 +++--- .../typescript/analysis_json/v2/README.md | 11 +++++++- .../analysis_json/v2/a1/analysis.json | 2 +- .../analysis_json/v2/a2/analysis.json | 2 +- .../analysis_json/v2/a3/analysis.json | 2 +- .../analysis_json/v2/a4/analysis.json | 2 +- uv.lock | 22 +++++++-------- 13 files changed, 82 insertions(+), 44 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 95db528f..8a80c89c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,7 +12,7 @@ an optional read-only Neo4j backend — selected by the *type* of the `backend=` |----------|-------------|---------------|---------------|--------| | Java | `CLDK.java(...)` (needs the `cldk[java]` extra) | `JCodeanalyzer` (the `codeanalyzer-java` 3.2.0 wheel's jar on its bundled JVM, subprocess, `-a 1..4` — no jar in this repo, no JDK download) | `JNeo4jBackend` (graphs emitted by ≥ 3.2.0, probed at attach) | `cldk/models/java/` (schema v2 mirror) + `projections.py` | | Python | `CLDK.python(...)` | `PyCodeanalyzer` (in-process `codeanalyzer-python`) | `PyNeo4jBackend` | re-exported from `codeanalyzer-python` | -| TypeScript (+ JavaScript modules) | `CLDK.typescript(...)` | `TSCodeanalyzer` (`codeanalyzer-typescript` 1.5.2 binary from the wheel, subprocess; `-a 1..4`, but `--emit neo4j` takes no `-a` and is always full depth) | `TSNeo4jBackend` (graphs emitted by ≥ 1.5.2; older refused at attach) | `cldk/models/typescript/` (schema v2 mirror) | +| TypeScript (+ JavaScript modules) | `CLDK.typescript(...)` | `TSCodeanalyzer` (`codeanalyzer-typescript` 1.6.0 binary from the wheel, subprocess; `-a 1..4`, but `--emit neo4j` takes no `-a` and is always full depth) | `TSNeo4jBackend` (graphs emitted by ≥ 1.5.2; older refused at attach) | `cldk/models/typescript/` (schema v2 mirror) | **Java, since leg 3a (#310):** the models are an `extra="forbid"` mirror of canonical schema v2, so a 1.x `analysis.json` (and a pre-3.0.1 Neo4j graph) is refused, not parsed; `get_call_graph()` keys diff --git a/cldk/analysis/python/neo4j/neo4j_backend.py b/cldk/analysis/python/neo4j/neo4j_backend.py index da227e32..ec977e1d 100644 --- a/cldk/analysis/python/neo4j/neo4j_backend.py +++ b/cldk/analysis/python/neo4j/neo4j_backend.py @@ -75,10 +75,14 @@ dangling reference and is silently dropped by the writer. Those edges never reach Neo4j, so the call graph here can be missing a small fraction of external-target edges. This is a producer bug, not a query bug. -* **Projection-lossy fields** (inherent to what the graph stores — see :mod:`reconstruct`): comments +* **Projection-lossy fields** (what this backend reads back — see :mod:`reconstruct`): comments collapse to a single docstring (module-level comments dropped); ``PyVariableDeclaration.value`` and - its column span, plus per-binding import detail, are not recoverable; the order of ``call_graph`` + its column span, plus per-binding import detail, come back empty; the order of ``call_graph`` edges and a callable's ``call_sites`` / ``local_variables`` is positional, not insertion order. + All but the comments stopped being the graph's limit at codeanalyzer-python 1.5.2, which projects + ``:PyVariable.value_json``, all six span properties wherever a span is declared, and + ``PY_IMPORTS.positions_json``; taking them up is python-sdk#396, and the floor stays 1.5.0 until + it does, so a served graph may not carry them either. Everything else round-trips identically to ``PyCodeanalyzer``. """ diff --git a/cldk/analysis/python/neo4j/reconstruct.py b/cldk/analysis/python/neo4j/reconstruct.py index 165377b9..0172a6b5 100644 --- a/cldk/analysis/python/neo4j/reconstruct.py +++ b/cldk/analysis/python/neo4j/reconstruct.py @@ -29,10 +29,19 @@ * Comments collapse to a single ``docstring`` string. We rebuild one ``PyComment(is_docstring=True)``; non-docstring comments, multiplicity and positions are not recoverable. Module-level comments are not projected at all, so ``PyModule.comments`` comes back empty. -* ``PyVariableDeclaration.value`` and ``start_column`` / ``end_column`` are not projected (only - ``initializer`` and the line span are), so they rehydrate as ``None`` / ``-1``. +* ``PyVariableDeclaration.value`` rehydrates as ``None`` and its columns as ``-1``: this module + reads ``initializer`` and the line span only. * ``PyModule.imports`` are reconstructed from the *aggregated* ``PY_IMPORTS`` edges (per-binding alias pairing and positions are lost). + +The last two were the projection's limits until codeanalyzer-python 1.5.2, which added +``:PyModule.source``, all six span properties (``start_column`` / ``end_column`` / ``start_byte`` / +``end_byte`` beside the line pair) wherever a span is declared, ``:PyVariable.value_json``, +``:PyBodyNode.callee_signature``, ``PY_IMPORTS.positions_json`` and a span on ``PY_DECORATED_BY``. +Reading them is python-sdk#396; until it lands they are the *backend's* limits, not the graph's, and +the attach floor stays 1.5.0, so a served graph may well not carry them. The one that already flows +free is a call site's columns -- :func:`callsite` reads them with a ``-1`` default, so a 1.5.2 graph +supplies them and an older one does not. """ from __future__ import annotations @@ -129,10 +138,12 @@ def callsite(props: Props, *, callee_signature: str | None = None) -> PyCallsite 1.4.0 emits one call site as a body node (#120), not a dedicated ``:PyCallSite`` label — the graph carries ``method_name`` / ``receiver_expr`` / ``receiver_type`` / ``return_type`` / - ``is_constructor_call`` and the line span, same as before. It does not project - ``argument_types`` or ``start_column``/``end_column`` — those fall back to their existing - empty/``-1`` defaults below, the same "projection-lossy field" shape as everything else in - this module. + ``is_constructor_call`` and the line span, same as before. ``argument_types`` is not projected at + all and falls back to its empty default below, the same "projection-lossy field" shape as + everything else in this module. ``start_column`` / ``end_column`` are read with a ``-1`` + default, so they are real on a graph emitted by codeanalyzer-python 1.5.2 or newer (which + projects all six span properties) and ``-1`` on anything older -- the floor is 1.5.0, so both + shapes are served. ``callee_signature`` is NOT one of ``props`` (the call node itself carries no such property — callee resolution lives on the separate ``PY_RESOLVES_TO`` edge to the resolved target, a @@ -168,8 +179,9 @@ def external_symbol(props: Props) -> PyExternalSymbol: def body_node(props: Props) -> BodyNode: """Rebuild a :class:`BodyNode` from a ``:PyBodyNode`` node's properties. - Line-only ``span``: the projection writes ``start_line`` / ``end_line`` and nothing finer, so - the columns and UTF-8 ``bytes`` offsets rehydrate as ``0`` — the same projection-lossy shape as + Line-only ``span``: this function reads ``start_line`` / ``end_line`` and nothing finer, so + the columns and UTF-8 ``bytes`` offsets rehydrate as ``0`` (codeanalyzer-python 1.5.2 projects + them; taking them up is python-sdk#396) — the same projection-lossy shape as :func:`callsite`, and the reason ``LocateResult.span`` documents which of its fields are real per backend. ``span`` stays ``None`` when the node carries no lines at all: the emitter prunes them from synthetic analysis vertices (``@entry`` / ``@exit`` / ``@formal_in:N``), which have no diff --git a/cldk/analysis/typescript/neo4j/neo4j_backend.py b/cldk/analysis/typescript/neo4j/neo4j_backend.py index 70bfc3f0..1c2cb8d6 100644 --- a/cldk/analysis/typescript/neo4j/neo4j_backend.py +++ b/cldk/analysis/typescript/neo4j/neo4j_backend.py @@ -16,7 +16,8 @@ """Neo4j-backed TypeScript analysis backend (read-only Cypher client) on the codeanalyzer-typescript schema-v2 graph vocabulary -- 1.2.0's ``can://`` grammar with the application moved outermost in -1.5.1, through the 1.5.2 pin. +1.5.1, through the 1.6.0 pin (the graph floor stays 1.5.2 -- the pin is what the SDK installs, +the floor what it requires of a graph). A drop-in alternative to :class:`TSCodeanalyzer`: the same query surface, every method answered by Cypher over a live graph that ``codeanalyzer-typescript --emit neo4j`` populated out of band. This diff --git a/cldk/analysis/typescript/neo4j/reconstruct.py b/cldk/analysis/typescript/neo4j/reconstruct.py index 5e84ab78..531270d7 100644 --- a/cldk/analysis/typescript/neo4j/reconstruct.py +++ b/cldk/analysis/typescript/neo4j/reconstruct.py @@ -26,12 +26,19 @@ What the projection does **not** carry, and therefore comes back at the model's empty default (verified against the schema and the live graph, not assumed): -* ``TSModule.source`` -- the graph stores each node's own ``code`` text and its line span, never - the module text or byte offsets. A reconstructed node's ``span`` is therefore line-only +* ``TSModule.source`` -- this module reads each node's own ``code`` text and its line span, and + neither the module text nor byte offsets. A reconstructed node's ``span`` is therefore line-only (columns ``0``) with ``bytes = (0, len(code))``, and its private ``_source`` is set to its own ``code`` so the model's ``code`` property reads the text the graph projected for that node (``None`` when the graph carries none). A module is assembled with ``model_construct`` so the module-level source threading (which would overwrite that with ``""``) does not run. + + Since codeanalyzer-typescript 1.6.0 the graph *does* carry ``:TSModule.source`` (the whole file, + ``""`` only for an empty one) plus ``start_column`` / ``end_column`` / ``start_byte`` / + ``end_byte`` on all ten spanned labels, so this is the backend's ceiling now rather than the + projection's -- python-sdk#391 is taking it up, and the attach floor stays 1.5.2 meanwhile, so a + served graph may carry none of it. ``:TSCallable.code`` is kept upstream precisely because this + path reads it (codeanalyzer-typescript#204). * ``TSCallable.comments``, ``type_parameters``, ``overload_signatures``, ``body``, ``cfg``/``cdg``/``ddg``/``summary`` -- ``:TSCallable`` projects none of them; the call view is answered from ``:TSBodyNode {kind:'call'}`` by the backend's call-site accessors, not stored on diff --git a/docs/agent-api-reference.md b/docs/agent-api-reference.md index 1f6b0e0f..a8173c15 100644 --- a/docs/agent-api-reference.md +++ b/docs/agent-api-reference.md @@ -46,8 +46,9 @@ disconnected old copy that the new application-prefix delete cannot reach. ## TypeScript -Status: leg 2.5b (`codeanalyzer-typescript` 1.5.2 pinned; graphs emitted by 1.5.2 or newer -served — see the floor below). What attaches +Status: leg 2.5b (`codeanalyzer-typescript` 1.6.0 pinned; graphs emitted by 1.5.2 or newer +served — the pin is what the SDK installs and the floor what it requires, two numbers that move +independently; see the floor below). What attaches today is the **1.x accessor surface** — symbol table, classes / interfaces / enums / type aliases / namespaces, methods, fields, call graph, call sites, decorators, externals, synthesized callables, the four bulk accessors and the repository-artifact layer — on both backends. @@ -154,12 +155,12 @@ documented empty comes back. | `get_application_view().param_in` / `.param_out` | empty — leg 2.5a reads **no** dataflow overlay (2.5b does). `.config_reads` and `.unresolved_imports` are empty for their own reasons: the config-read edge carries no `site`, so the view's entries would not be the ones in-process holds (`get_unresolved_config_reads()` is where they are reachable), and no accessor reads `TS_UNRESOLVED_IMPORT`. `.artifacts` / `.dependencies` / `.config_uses` **are** populated, from the same rows the dedicated accessors return | | `TSCallable.comments`, `type_parameters`, `overload_signatures`, `body`, `cfg`/`cdg`/`ddg`/`summary` | empty. `parameters` are populated from `parameters_json` on a 1.4.0 graph | | `TSEnumMember.value`; `TSModule.source` / `imports` / `comments`; decorator positions; a call site's `method_name`, receiver and argument facets | empty / `None`. `TSModule.exports` **is** populated from `exports_json`; `imports` stay empty on a rebuilt module — they live on edges the containment fetch does not walk, and `get_imports()` is what reads them | -| `code` on any node | the text the graph projected for that node, on a line-only span (columns `0`) | +| `code` on any node | the text the graph projected for that node, on a line-only span (columns `0`). codeanalyzer-typescript 1.6.0 added `start_column` / `end_column` / `start_byte` / `end_byte` to every spanned label; this backend does not read them yet (#391) | | `get_call_targets(sig)` | an unresolved call site contributes `""` (in-memory: the call's `method_name`) | | `get_synthesized_callables()` | keyed by the anonymous node's own id (the analyzer's older compatibility key is JSON-only) | -| `locate(path, line)` at module scope | `source == ""` plus a second `module_source_unavailable` diagnostic — `:TSModule` carries no `source`. In-memory: the module's text | -| `get_source(node_id)` for a **body-node** id | **raises `NotImplementedError`** — the graph carries no text below callable granularity. In-memory: the span's slice | -| `LocateResult.span` columns and byte offsets | placeholders; lines are real on both backends | +| `locate(path, line)` at module scope | `source == ""` plus a second `module_source_unavailable` diagnostic. `:TSModule` **does** carry `source` since codeanalyzer-typescript 1.6.0 — this backend does not read it yet (#391), and the graph floor is 1.5.2, so a served graph may legitimately not have it either. In-memory: the module's text | +| `get_source(node_id)` for a **body-node** id | **raises `NotImplementedError`** — this backend resolves no text below callable granularity: `:TSBodyNode` projects no `code`, and the module source plus byte offsets that would let it slice one (1.6.0) are unread (#391). In-memory: the span's slice | +| `LocateResult.span` columns and byte offsets | placeholders; lines are real on both backends. Carried by a 1.6.0 graph, unread here (#391) | | `get_entrypoint_coverage()` | the anchor's `entrypoint_report_json` string, parsed — same report as in-memory, no lossiness. A graph without the property answers `entrypoint_report_unavailable` rather than empty-but-clean fields | Two more hold on **both** backends. `get_entrypoint_classes()` covers **classes only**: the wire @@ -506,9 +507,13 @@ class LocateResult: | between two callables | same as module scope; it never snaps to the nearest callable | | file not analysed | diagnostic `file_not_in_graph` — distinct from a file that doesn't exist | -**Gotcha:** over Neo4j, module-scope `source` is empty and carries `module_source_unavailable`. -`:PyModule` nodes genuinely do not store source text. The local backend returns it. Do not read -an empty `source` as "no code there". +**Gotcha:** on **Python and TypeScript** over Neo4j, module-scope `source` is empty and carries +`module_source_unavailable`; the local backend returns it. Do not read an empty `source` as "no code +there". The graph stopped being the reason: `:PyModule.source` lands in codeanalyzer-python 1.5.2 and +`:TSModule.source` in codeanalyzer-typescript 1.6.0, and these two backends do not read it yet +(#396, #391). **Java** is the one that does, since codeanalyzer-java 3.2.0: module-scope `source` is +the file's text on both of its backends, and the diagnostic is left for a module whose text the +analyzer could not read. --- @@ -930,7 +935,7 @@ Any accessor may attach these. They exist so an empty result is never ambiguous. | --- | --- | | `module_scope` | the position is real, but outside any callable | | `file_not_in_graph` | the file was not analysed — not "does not exist" | -| `module_source_unavailable` | this backend cannot supply module text (Neo4j) | +| `module_source_unavailable` | the backend cannot supply module text — Python and TypeScript over Neo4j always (#396, #391); Java only where the analyzer could not read the file | | `entrypoint_report_unavailable` | **you cannot tell whether an empty entrypoint list is real** | | `level_too_low` | the graph lacks the analysis level this question needs — *unanswerable, not negative* | | `graph_schema_mismatch` | analyzer/graph generation mismatch (raised, not attached) | diff --git a/pyproject.toml b/pyproject.toml index 801b4c3d..da8b19e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,8 +35,8 @@ dependencies = [ "tree-sitter-java==0.23.5", "tree-sitter-python==0.23.6", "tree-sitter-javascript==0.23.1", - "codeanalyzer-python==1.5.1", - "codeanalyzer-typescript==1.5.3", + "codeanalyzer-python==1.5.2", + "codeanalyzer-typescript==1.6.0", ] [project.optional-dependencies] @@ -87,8 +87,8 @@ include = [ [tool.backend-versions] codeanalyzer-java = "3.2.0" -codeanalyzer-python = "1.5.1" -codeanalyzer-typescript = "1.5.3" +codeanalyzer-python = "1.5.2" +codeanalyzer-typescript = "1.6.0" ######################################## # Tool configurations diff --git a/tests/resources/typescript/analysis_json/v2/README.md b/tests/resources/typescript/analysis_json/v2/README.md index f647e79a..26ea20cd 100644 --- a/tests/resources/typescript/analysis_json/v2/README.md +++ b/tests/resources/typescript/analysis_json/v2/README.md @@ -1,4 +1,4 @@ -Generated from `tests/resources/typescript/application` by the released **codeanalyzer-typescript 1.5.3** wheel: +Generated from `tests/resources/typescript/application` by the released **codeanalyzer-typescript 1.6.0** wheel: cants -i tests/resources/typescript/application --app-name slim -a <1|2|3|4> -o a --cache-dir -j 1 --no-build @@ -38,3 +38,12 @@ Why it mattered: the schemas had declared the property since the L4 layer landed wrote nothing, so a consumer predicate on `var` was `null` on every edge crossing a call boundary. Under Cypher's three-valued logic an `all()` over that `null` excludes the whole path, so an interprocedural flow read as a proved absence of flow -- indistinguishable from a real negative. + +What 1.6.0 changed against the 1.5.3 generation these files held before: **nothing in this output**. +All four levels are byte-identical apart from the `analyzer.version` stamp, checked by parsing both +generations and comparing them with that one field masked. 1.6.0 is a Neo4j-projection release +(codeanalyzer-typescript#204): `:TSModule` gains `source`, the shared `SPAN` gains `start_column` / +`end_column` / `start_byte` / `end_byte` across ten labels, and `:TSAnonymousCallable` stops writing +a half-span by hand. `analysis.json` already carried every one of those facts, which is why the +regeneration moves only the stamp — and why the pin bump is not a read-path change. `:TSCallable.code` +is kept upstream on purpose: this SDK's Neo4j reconstruction reads it. diff --git a/tests/resources/typescript/analysis_json/v2/a1/analysis.json b/tests/resources/typescript/analysis_json/v2/a1/analysis.json index 6079cc19..da16a358 100644 --- a/tests/resources/typescript/analysis_json/v2/a1/analysis.json +++ b/tests/resources/typescript/analysis_json/v2/a1/analysis.json @@ -1 +1 @@ -{"schema_version":"2.0.0","language":"typescript","max_level":1,"analyzer":{"name":"codeanalyzer-typescript","version":"1.5.3"},"application":{"id":"can://slim","kind":"application","symbol_table":{"src/controllers.ts":{"id":"can://slim/typescript/src/controllers.ts","kind":"module","span":{"start":[1,1],"end":[29,1],"bytes":[0,699]},"source":"import { UserService } from \"./services\";\n\n// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.\nfunction Controller(prefix: string): ClassDecorator {\n return () => undefined;\n}\nfunction Get(path: string): MethodDecorator {\n return () => undefined;\n}\nfunction Param(name: string): ParameterDecorator {\n return () => undefined;\n}\n\n@Controller(\"/users\")\nexport class UserController {\n constructor(private readonly service: UserService) {}\n\n @Get(\"/:id\")\n show(@Param(\"id\") id: string): string {\n const user = this.service.create(id);\n return user.describe();\n }\n\n @Get(\"/\")\n list(): string[] {\n return this.service.describeAll();\n }\n}\n","imports":[{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":42,"resolved_module":"src/services.ts"}],"exports":[],"comments":[{"content":"// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.","is_docstring":false,"start_line":3,"end_line":3,"start_column":1,"end_column":101}],"types":{"UserController":{"id":"can://slim/typescript/src/controllers.ts/UserController","kind":"class","span":{"start":[14,1],"end":[28,2],"bytes":[380,698]},"name":"UserController","signature":"src/controllers.UserController","comments":[],"decorators":[{"name":"Controller","positional_arguments":["\"/users\""],"keyword_arguments":{},"start_line":14,"end_line":14,"start_column":1,"end_column":22}],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"show":{"id":"can://slim/typescript/src/controllers.ts/UserController/show","kind":"method","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"name":"show","signature":"src/controllers.UserController.show","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/:id\""],"keyword_arguments":{},"start_line":18,"end_line":18,"start_column":3,"end_column":15}],"parameters":[{"name":"id","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[{"name":"Param","positional_arguments":["\"id\""],"keyword_arguments":{},"start_line":19,"end_line":19,"start_column":8,"end_column":20}],"start_line":19,"end_line":19,"start_column":8,"end_column":31,"id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"20:18":{"kind":"call","span":{"start":[20,18],"end":[20,41],"bytes":[563,586]},"callee":null,"method_name":"create","receiver_expr":"this.service","receiver_type":"UserService","argument_types":["string"],"type_arguments":[],"return_type":"import(\"./models\").User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:18"},"21:12":{"kind":"call","span":{"start":[21,12],"end":[21,27],"bytes":[599,614]},"callee":null,"method_name":"describe","receiver_expr":"user","receiver_type":"import(\"./models\").User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:12"},"19:9":{"kind":"call","span":{"start":[19,9],"end":[19,20],"bytes":[512,523]},"callee":null,"method_name":"Param","argument_types":["\"id\""],"type_arguments":[],"return_type":"ParameterDecorator","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@19:9"}},"entrypoints":[],"is_entrypoint":false},"list":{"id":"can://slim/typescript/src/controllers.ts/UserController/list","kind":"method","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"name":"list","signature":"src/controllers.UserController.list","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/\""],"keyword_arguments":{},"start_line":24,"end_line":24,"start_column":3,"end_column":12}],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,38],"bytes":[665,691]},"callee":null,"method_name":"describeAll","receiver_expr":"this.service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:12"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/controllers.ts/UserController/constructor","kind":"constructor","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"name":"constructor","signature":"src/controllers.UserController.constructor","comments":[],"decorators":[],"parameters":[{"name":"service","type":"UserService","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":16,"end_line":16,"start_column":15,"end_column":52,"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"service":{"id":"can://slim/typescript/src/controllers.ts/UserController/service","kind":"field","name":"service","type":"UserService","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"Controller":{"id":"can://slim/typescript/src/controllers.ts/Controller","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"name":"Controller","signature":"src/controllers.Controller","comments":[],"decorators":[],"parameters":[{"name":"prefix","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":21,"end_column":35,"id":"can://slim/typescript/src/controllers.ts/Controller@formal_in:0"}],"type_parameters":[],"return_type":"ClassDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"arrow","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"name":"(anonymous)","signature":"src/controllers.Controller.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"Get":{"id":"can://slim/typescript/src/controllers.ts/Get","kind":"function","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"name":"Get","signature":"src/controllers.Get","comments":[],"decorators":[],"parameters":[{"name":"path","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":14,"end_column":26,"id":"can://slim/typescript/src/controllers.ts/Get@formal_in:0"}],"type_parameters":[],"return_type":"MethodDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"arrow","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"name":"(anonymous)","signature":"src/controllers.Get.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"Param":{"id":"can://slim/typescript/src/controllers.ts/Param","kind":"function","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"name":"Param","signature":"src/controllers.Param","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":10,"end_line":10,"start_column":16,"end_column":28,"id":"can://slim/typescript/src/controllers.ts/Param@formal_in:0"}],"type_parameters":[],"return_type":"ParameterDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"arrow","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"name":"(anonymous)","signature":"src/controllers.Param.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d42b8f615d51575e3436409b9fce70862182b6071da40471b4be9b95f7c9ee4c"},"src/index.ts":{"id":"can://slim/typescript/src/index.ts","kind":"module","span":{"start":[1,1],"end":[26,1],"bytes":[0,742]},"source":"import { UserController } from \"./controllers\";\nimport { Robot, Role, User } from \"./models\";\nimport { UserService, announce } from \"./services\";\nimport { StringUtil } from \"./util\";\n\nexport function main(): void {\n const service = new UserService(100);\n service.create(\"Ada\", Role.Admin);\n service.createGuest();\n\n const controller = new UserController(service);\n controller.list();\n controller.show(\"42\");\n\n // interface-typed dispatch — RTA should expand announce -> {User,Robot}.describe\n announce(new User(1, \"Ada\", Role.Admin));\n announce(new Robot(\"r2d2\"));\n\n const slug = StringUtil.repeat(\"hello world\", 2);\n const builder = new StringUtil.Builder();\n builder.add(\"a\").add(\"b\").build();\n console.log(slug);\n}\n\nmain();\n","imports":[{"module":"./controllers","name":"UserController","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":48,"resolved_module":"src/controllers.ts"},{"module":"./models","name":"Robot","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./services","name":"announce","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./util","name":"StringUtil","is_type_only":false,"import_kind":"named","start_line":4,"end_line":4,"start_column":1,"end_column":37,"resolved_module":"src/util.ts"}],"exports":[],"comments":[],"types":{},"functions":{"main":{"id":"can://slim/typescript/src/index.ts/main","kind":"function","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"name":"main","signature":"src/index.main","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"void","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"7:19":{"kind":"call","span":{"start":[7,19],"end":[7,39],"bytes":[233,253]},"callee":null,"method_name":"UserService","argument_types":["100"],"type_arguments":[],"return_type":"UserService","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@7:19"},"8:3":{"kind":"call","span":{"start":[8,3],"end":[8,36],"bytes":[257,290]},"callee":null,"method_name":"create","receiver_expr":"service","receiver_type":"UserService","argument_types":["\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@8:3"},"9:3":{"kind":"call","span":{"start":[9,3],"end":[9,24],"bytes":[294,315]},"callee":null,"method_name":"createGuest","receiver_expr":"service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@9:3"},"11:22":{"kind":"call","span":{"start":[11,22],"end":[11,49],"bytes":[339,366]},"callee":null,"method_name":"UserController","argument_types":["UserService"],"type_arguments":[],"return_type":"UserController","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@11:22"},"12:3":{"kind":"call","span":{"start":[12,3],"end":[12,20],"bytes":[370,387]},"callee":null,"method_name":"list","receiver_expr":"controller","receiver_type":"UserController","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@12:3"},"13:3":{"kind":"call","span":{"start":[13,3],"end":[13,24],"bytes":[391,412]},"callee":null,"method_name":"show","receiver_expr":"controller","receiver_type":"UserController","argument_types":["\"42\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@13:3"},"16:3":{"kind":"call","span":{"start":[16,3],"end":[16,43],"bytes":[503,543]},"callee":null,"method_name":"announce","argument_types":["User"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:3"},"16:12":{"kind":"call","span":{"start":[16,12],"end":[16,42],"bytes":[512,542]},"callee":null,"method_name":"User","argument_types":["1","\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:12"},"17:3":{"kind":"call","span":{"start":[17,3],"end":[17,30],"bytes":[547,574]},"callee":null,"method_name":"announce","argument_types":["Robot"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:3"},"17:12":{"kind":"call","span":{"start":[17,12],"end":[17,29],"bytes":[556,573]},"callee":null,"method_name":"Robot","argument_types":["\"r2d2\""],"type_arguments":[],"return_type":"Robot","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:12"},"19:16":{"kind":"call","span":{"start":[19,16],"end":[19,51],"bytes":[592,627]},"callee":null,"method_name":"repeat","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":["\"hello world\"","2"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@19:16"},"20:19":{"kind":"call","span":{"start":[20,19],"end":[20,43],"bytes":[647,671]},"callee":null,"method_name":"Builder","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":[],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@20:19"},"21:3":{"kind":"call","span":{"start":[21,3],"end":[21,36],"bytes":[675,708]},"callee":null,"method_name":"build","receiver_expr":"builder.add(\"a\").add(\"b\")","receiver_type":"StringUtil.Builder","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3"},"21:3/2":{"kind":"call","span":{"start":[21,3],"end":[21,28],"bytes":[675,700]},"callee":null,"method_name":"add","receiver_expr":"builder.add(\"a\")","receiver_type":"StringUtil.Builder","argument_types":["\"b\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/2"},"21:3/3":{"kind":"call","span":{"start":[21,3],"end":[21,19],"bytes":[675,691]},"callee":null,"method_name":"add","receiver_expr":"builder","receiver_type":"StringUtil.Builder","argument_types":["\"a\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/3"},"22:3":{"kind":"call","span":{"start":[22,3],"end":[22,20],"bytes":[712,729]},"callee":null,"method_name":"log","receiver_expr":"console","receiver_type":"Console","argument_types":["string"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@22:3"}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"6de6f6ff5a01a5c7c750a93d5e10bae7b15817f386421f45c7527cfb7259d9b3"},"src/models.ts":{"id":"can://slim/typescript/src/models.ts","kind":"module","span":{"start":[1,1],"end":[65,1],"bytes":[0,1237]},"source":"/** Domain models for the sample app. */\n\nexport interface Identifiable {\n readonly id: T;\n}\n\nexport interface Named {\n name: string;\n describe(): string;\n}\n\nexport type UserId = string | number;\n\nexport enum Role {\n Admin = \"admin\",\n Member = \"member\",\n Guest = \"guest\",\n}\n\nexport const enum Flag {\n None = 0,\n Active = 1,\n}\n\n/** A user of the system. */\nexport abstract class Entity implements Identifiable {\n constructor(public readonly id: ID) {}\n abstract describe(): string;\n}\n\nexport class User extends Entity implements Named {\n private loginCount = 0;\n static instances = 0;\n\n constructor(\n id: UserId,\n public name: string,\n private role: Role = Role.Member,\n ) {\n super(id);\n User.instances++;\n }\n\n get isAdmin(): boolean {\n return this.role === Role.Admin;\n }\n\n describe(): string {\n return `${this.name} (${this.role})`;\n }\n\n async recordLogin(): Promise {\n this.loginCount += 1;\n return this.loginCount;\n }\n}\n\n/** A second, unrelated implementer of Named — drives RTA subtype expansion. */\nexport class Robot implements Named {\n constructor(public name: string) {}\n describe(): string {\n return `robot:${this.name}`;\n }\n}\n","imports":[],"exports":[],"comments":[{"content":"/** Domain models for the sample app. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41},{"content":"/** A user of the system. */","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29},{"content":"/** A second, unrelated implementer of Named — drives RTA subtype expansion. */","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"types":{"Entity":{"id":"can://slim/typescript/src/models.ts/Entity","kind":"class","span":{"start":[26,1],"end":[29,2],"bytes":[376,521]},"name":"Entity","signature":"src/models.Entity","comments":[{"content":"A user of the system.","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29}],"decorators":[],"base_classes":["src/models.Identifiable"],"implements_types":["src/models.Identifiable"],"type_parameters":[{"name":"ID","default":"string"}],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Entity/describe","kind":"method","span":{"start":[28,3],"end":[28,31],"bytes":[491,519]},"name":"describe","signature":"src/models.Entity.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":true,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[{"parameters":[],"return_type":"string","type_parameters":[],"start_line":28,"end_line":28}],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Entity/constructor","kind":"constructor","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"name":"constructor","signature":"src/models.Entity.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"ID","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"public","decorators":[],"start_line":27,"end_line":27,"start_column":15,"end_column":37,"id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Entity/id","kind":"field","name":"id","type":"ID","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":true,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Identifiable"],"entrypoints":[],"is_entrypoint":false},"User":{"id":"can://slim/typescript/src/models.ts/User","kind":"class","span":{"start":[31,1],"end":[56,2],"bytes":[523,1015]},"name":"User","signature":"src/models.User","comments":[],"decorators":[],"base_classes":["src/models.Entity","src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/User/describe","kind":"method","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"name":"describe","signature":"src/models.User.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"recordLogin":{"id":"can://slim/typescript/src/models.ts/User/recordLogin","kind":"method","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"name":"recordLogin","signature":"src/models.User.recordLogin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/User/constructor","kind":"constructor","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"name":"constructor","signature":"src/models.User.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"UserId","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":36,"end_line":36,"start_column":5,"end_column":15,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0"},{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":37,"end_line":37,"start_column":5,"end_column":24,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"accessibility":"private","decorators":[],"start_line":38,"end_line":38,"start_column":5,"end_column":37,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"40:5":{"kind":"call","span":{"start":[40,5],"end":[40,14],"bytes":[738,747]},"callee":null,"method_name":"super","argument_types":["UserId"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/models.ts/User/constructor@40:5"}},"entrypoints":[],"is_entrypoint":false},"isAdmin#get":{"id":"can://slim/typescript/src/models.ts/User/isAdmin","kind":"getter","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"name":"isAdmin","signature":"src/models.User.isAdmin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"boolean","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"accessor_kind":"getter","overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"loginCount":{"id":"can://slim/typescript/src/models.ts/User/loginCount","kind":"field","span":{"start":[32,3],"end":[32,26],"bytes":[585,608]},"name":"loginCount","type":"number","comments":[],"decorators":[],"initializer":"0","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"instances":{"id":"can://slim/typescript/src/models.ts/User/instances","kind":"field","span":{"start":[33,3],"end":[33,24],"bytes":[611,632]},"name":"instances","type":"number","comments":[],"decorators":[],"initializer":"0","is_static":true,"is_readonly":false,"is_optional":false,"is_abstract":false},"name":{"id":"can://slim/typescript/src/models.ts/User/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"role":{"id":"can://slim/typescript/src/models.ts/User/role","kind":"field","name":"role","type":"Role","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":false,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"extends_ids":["can://slim/typescript/src/models.ts/Entity"],"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Robot":{"id":"can://slim/typescript/src/models.ts/Robot","kind":"class","span":{"start":[59,1],"end":[64,2],"bytes":[1099,1236]},"name":"Robot","signature":"src/models.Robot","comments":[{"content":"A second, unrelated implementer of Named — drives RTA subtype expansion.","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"decorators":[],"base_classes":["src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Robot/describe","kind":"method","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"name":"describe","signature":"src/models.Robot.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Robot/constructor","kind":"constructor","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"name":"constructor","signature":"src/models.Robot.constructor","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":60,"end_line":60,"start_column":15,"end_column":34,"id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Robot/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Identifiable":{"id":"can://slim/typescript/src/models.ts/Identifiable","kind":"interface","span":{"start":[3,1],"end":[5,2],"bytes":[42,105]},"name":"Identifiable","signature":"src/models.Identifiable","comments":[{"content":"Domain models for the sample app.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41}],"base_classes":[],"type_parameters":[{"name":"T","default":"string"}],"callables":{},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Identifiable/id","kind":"field","span":{"start":[4,3],"end":[4,18],"bytes":[88,103]},"name":"id","type":"T","comments":[],"decorators":[],"is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Named":{"id":"can://slim/typescript/src/models.ts/Named","kind":"interface","span":{"start":[7,1],"end":[10,2],"bytes":[107,171]},"name":"Named","signature":"src/models.Named","comments":[],"base_classes":[],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Named/describe","kind":"method","span":{"start":[9,3],"end":[9,22],"bytes":[150,169]},"name":"describe","signature":"src/models.Named.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Named/name","kind":"field","span":{"start":[8,3],"end":[8,16],"bytes":[134,147]},"name":"name","type":"string","comments":[],"decorators":[],"is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Role":{"id":"can://slim/typescript/src/models.ts/Role","kind":"enum","span":{"start":[14,1],"end":[18,2],"bytes":[212,291]},"name":"Role","signature":"src/models.Role","comments":[],"fields":{"Admin":{"id":"can://slim/typescript/src/models.ts/Role/Admin","kind":"field","span":{"start":[15,3],"end":[15,18],"bytes":[233,248]},"name":"Admin","value":"admin"},"Member":{"id":"can://slim/typescript/src/models.ts/Role/Member","kind":"field","span":{"start":[16,3],"end":[16,20],"bytes":[252,269]},"name":"Member","value":"member"},"Guest":{"id":"can://slim/typescript/src/models.ts/Role/Guest","kind":"field","span":{"start":[17,3],"end":[17,18],"bytes":[273,288]},"name":"Guest","value":"guest"}},"is_const":false,"is_exported":true,"is_ambient":false},"Flag":{"id":"can://slim/typescript/src/models.ts/Flag","kind":"enum","span":{"start":[20,1],"end":[23,2],"bytes":[293,345]},"name":"Flag","signature":"src/models.Flag","comments":[],"fields":{"None":{"id":"can://slim/typescript/src/models.ts/Flag/None","kind":"field","span":{"start":[21,3],"end":[21,11],"bytes":[320,328]},"name":"None","value":"0"},"Active":{"id":"can://slim/typescript/src/models.ts/Flag/Active","kind":"field","span":{"start":[22,3],"end":[22,13],"bytes":[332,342]},"name":"Active","value":"1"}},"is_const":true,"is_exported":true,"is_ambient":false},"UserId":{"id":"can://slim/typescript/src/models.ts/UserId","kind":"type_alias","span":{"start":[12,1],"end":[12,38],"bytes":[173,210]},"name":"UserId","signature":"src/models.UserId","comments":[],"aliased_type":"string | number","type_parameters":[],"is_exported":true,"is_ambient":false}},"functions":{},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d39ff571ccfda4b7c46923586b6b94d0e818a51be966f1ba40305650fd0ffc91"},"src/services.ts":{"id":"can://slim/typescript/src/services.ts","kind":"module","span":{"start":[1,1],"end":[48,1],"bytes":[0,1240]},"source":"import { type Named, Role, User, type UserId } from \"./models\";\n\n/** Pure helper — top-level function. */\nexport function makeGuestName(seed: number): string {\n return `guest-${seed}`;\n}\n\n/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */\nexport function announce(thing: Named): string {\n return thing.describe();\n}\n\n/** Arrow function bound to a const (function_expression-style callable). */\nexport const nextId = (n: number): UserId => n + 1;\n\nexport class UserService {\n private users: User[] = [];\n\n constructor(private readonly startId: number = 0) {}\n\n create(name: string, role: Role = Role.Member): User {\n const id = nextId(this.users.length + this.startId);\n const user = new User(id, name, role);\n this.users.push(user);\n return user;\n }\n\n createGuest(): User {\n const name = makeGuestName(this.users.length);\n return this.create(name, Role.Guest);\n }\n\n describeAll(): string[] {\n return this.users.map((u) => u.describe());\n }\n\n async loginAll(): Promise {\n let total = 0;\n for (const u of this.users) {\n total += await u.recordLogin();\n }\n return total;\n }\n}\n","imports":[{"module":"./models","name":"Named","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"UserId","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"}],"exports":[],"comments":[{"content":"/** Pure helper — top-level function. */","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41},{"content":"/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4},{"content":"/** Arrow function bound to a const (function_expression-style callable). */","is_docstring":true,"start_line":16,"end_line":16,"start_column":1,"end_column":77}],"types":{"UserService":{"id":"can://slim/typescript/src/services.ts/UserService","kind":"class","span":{"start":[19,1],"end":[47,2],"bytes":[558,1239]},"name":"UserService","signature":"src/services.UserService","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"create":{"id":"can://slim/typescript/src/services.ts/UserService/create","kind":"method","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"name":"create","signature":"src/services.UserService.create","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":10,"end_column":22,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":24,"end_column":48,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1"}],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"25:16":{"kind":"call","span":{"start":[25,16],"end":[25,56],"bytes":[744,784]},"callee":null,"method_name":"nextId","argument_types":["number"],"type_arguments":[],"return_type":"UserId","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@25:16"},"26:18":{"kind":"call","span":{"start":[26,18],"end":[26,42],"bytes":[803,827]},"callee":null,"method_name":"User","argument_types":["UserId","string","Role"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@26:18"},"27:5":{"kind":"call","span":{"start":[27,5],"end":[27,26],"bytes":[833,854]},"callee":null,"method_name":"push","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["User"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@27:5"}},"entrypoints":[],"is_entrypoint":false},"createGuest":{"id":"can://slim/typescript/src/services.ts/UserService/createGuest","kind":"method","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"name":"createGuest","signature":"src/services.UserService.createGuest","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"32:18":{"kind":"call","span":{"start":[32,18],"end":[32,50],"bytes":[919,951]},"callee":null,"method_name":"makeGuestName","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:18"},"33:12":{"kind":"call","span":{"start":[33,12],"end":[33,41],"bytes":[964,993]},"callee":null,"method_name":"create","receiver_expr":"this","receiver_type":"this","argument_types":["string","Role.Guest"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:12"}},"entrypoints":[],"is_entrypoint":false},"describeAll":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll","kind":"method","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"name":"describeAll","signature":"src/services.UserService.describeAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:12":{"kind":"call","span":{"start":[37,12],"end":[37,47],"bytes":[1039,1074]},"callee":null,"method_name":"map","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["(u: User) => string"],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:12"}},"callables":{"":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"arrow","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"name":"(anonymous)","signature":"src/services.UserService.describeAll.","comments":[],"decorators":[],"parameters":[{"name":"u","type":"User","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":37,"end_line":37,"start_column":28,"end_column":29,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:34":{"kind":"call","span":{"start":[37,34],"end":[37,46],"bytes":[1061,1073]},"callee":null,"method_name":"describe","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34"}},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"loginAll":{"id":"can://slim/typescript/src/services.ts/UserService/loginAll","kind":"method","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"name":"loginAll","signature":"src/services.UserService.loginAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"43:22":{"kind":"call","span":{"start":[43,22],"end":[43,37],"bytes":[1193,1208]},"callee":null,"method_name":"recordLogin","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"Promise","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:22"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/services.ts/UserService/constructor","kind":"constructor","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"name":"constructor","signature":"src/services.UserService.constructor","comments":[],"decorators":[],"parameters":[{"name":"startId","type":"number","default_value":"0","is_optional":true,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":22,"end_line":22,"start_column":15,"end_column":51,"id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"users":{"id":"can://slim/typescript/src/services.ts/UserService/users","kind":"field","span":{"start":[20,3],"end":[20,30],"bytes":[587,614]},"name":"users","type":"User[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"startId":{"id":"can://slim/typescript/src/services.ts/UserService/startId","kind":"field","name":"startId","type":"number","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"makeGuestName":{"id":"can://slim/typescript/src/services.ts/makeGuestName","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"name":"makeGuestName","signature":"src/services.makeGuestName","comments":[{"content":"Pure helper — top-level function.","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41}],"decorators":[],"parameters":[{"name":"seed","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":31,"end_column":43,"id":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"announce":{"id":"can://slim/typescript/src/services.ts/announce","kind":"function","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"name":"announce","signature":"src/services.announce","comments":[{"content":"Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\nconcrete implementer of Named (User, Robot, ...).","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4}],"decorators":[],"parameters":[{"name":"thing","type":"Named","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":12,"end_line":12,"start_column":26,"end_column":38,"id":"can://slim/typescript/src/services.ts/announce@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"13:10":{"kind":"call","span":{"start":[13,10],"end":[13,26],"bytes":[407,423]},"callee":null,"method_name":"describe","receiver_expr":"thing","receiver_type":"Named","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/announce@13:10"}},"entrypoints":[],"is_entrypoint":false},"nextId":{"id":"can://slim/typescript/src/services.ts/nextId","kind":"arrow","span":{"start":[17,14],"end":[17,51],"bytes":[518,555]},"name":"nextId","signature":"src/services.nextId","comments":[],"decorators":[],"parameters":[{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":17,"end_line":17,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/services.ts/nextId@formal_in:0"}],"type_parameters":[],"return_type":"UserId","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"1bda3666dab48f8e686fb8ffc2143f2e422af62be46698053cfeea4184b55617"},"src/util.ts":{"id":"can://slim/typescript/src/util.ts","kind":"module","span":{"start":[1,1],"end":[35,1],"bytes":[0,949]},"source":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */\nexport namespace StringUtil {\n export function repeat(s: string, n: number): string {\n return slug(s).repeat(n);\n }\n\n export function slug(s: string): string {\n return s.toLowerCase().replace(/\\s+/g, \"-\");\n }\n\n export class Builder {\n private parts: string[] = [];\n add(part: string): this {\n this.parts.push(slug(part));\n return this;\n }\n build(): string {\n return this.parts.join(\"/\");\n }\n }\n}\n\n/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */\nexport function classify(items: T[]): Record {\n function keyOf(item: T): string {\n return item.name.charAt(0);\n }\n const out: Record = {};\n for (const item of items) {\n const k = keyOf(item);\n (out[k] ??= []).push(item);\n }\n return out;\n}\n","imports":[],"exports":[],"comments":[{"content":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106},{"content":"/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"types":{"StringUtil":{"id":"can://slim/typescript/src/util.ts/StringUtil","kind":"namespace","span":{"start":[2,1],"end":[21,2],"bytes":[106,543]},"name":"StringUtil","signature":"src/util.StringUtil","comments":[{"content":"A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106}],"types":{"Builder":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder","kind":"class","span":{"start":[11,3],"end":[20,4],"bytes":[328,541]},"name":"Builder","signature":"src/util.StringUtil.Builder","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"add":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","kind":"method","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"name":"add","signature":"src/util.StringUtil.Builder.add","comments":[],"decorators":[],"parameters":[{"name":"part","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":13,"end_line":13,"start_column":9,"end_column":21,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0"}],"type_parameters":[],"return_type":"this","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"14:7":{"kind":"call","span":{"start":[14,7],"end":[14,34],"bytes":[421,448]},"callee":null,"method_name":"push","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["string"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7"},"14:23":{"kind":"call","span":{"start":[14,23],"end":[14,33],"bytes":[437,447]},"callee":null,"method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:23"}},"entrypoints":[],"is_entrypoint":false},"build":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","kind":"method","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"name":"build","signature":"src/util.StringUtil.Builder.build","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"18:14":{"kind":"call","span":{"start":[18,14],"end":[18,34],"bytes":[510,530]},"callee":null,"method_name":"join","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["\"/\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:14"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","kind":"constructor","span":{"start":[0,0],"end":[0,0],"bytes":[0,0]},"name":"constructor","signature":"src/util.StringUtil.Builder.constructor","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":true,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"parts":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/parts","kind":"field","span":{"start":[12,5],"end":[12,34],"bytes":[355,384]},"name":"parts","type":"string[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"repeat":{"id":"can://slim/typescript/src/util.ts/StringUtil/repeat","kind":"function","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"name":"repeat","signature":"src/util.StringUtil.repeat","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":26,"end_column":35,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0"},{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":37,"end_column":46,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"4:12":{"kind":"call","span":{"start":[4,12],"end":[4,29],"bytes":[204,221]},"callee":null,"method_name":"repeat","receiver_expr":"slug(s)","receiver_type":"string","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12"},"4:12/2":{"kind":"call","span":{"start":[4,12],"end":[4,19],"bytes":[204,211]},"callee":null,"method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12/2"}},"entrypoints":[],"is_entrypoint":false},"slug":{"id":"can://slim/typescript/src/util.ts/StringUtil/slug","kind":"function","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"name":"slug","signature":"src/util.StringUtil.slug","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"8:12":{"kind":"call","span":{"start":[8,12],"end":[8,48],"bytes":[283,319]},"callee":null,"method_name":"replace","receiver_expr":"s.toLowerCase()","receiver_type":"string","argument_types":["RegExp","\"-\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12"},"8:12/2":{"kind":"call","span":{"start":[8,12],"end":[8,27],"bytes":[283,298]},"callee":null,"method_name":"toLowerCase","receiver_expr":"s","receiver_type":"string","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12/2"}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_exported":true,"is_ambient":false}},"functions":{"classify":{"id":"can://slim/typescript/src/util.ts/classify","kind":"function","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"name":"classify","signature":"src/util.classify","comments":[{"content":"Generic top-level function with a nested helper, to exercise inner_callables + generics.","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"decorators":[],"parameters":[{"name":"items","type":"T[]","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":54,"end_column":64,"id":"can://slim/typescript/src/util.ts/classify@formal_in:0"}],"type_parameters":[{"name":"T","constraint":"{ name: string }"}],"return_type":"Record","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"30:15":{"kind":"call","span":{"start":[30,15],"end":[30,26],"bytes":[884,895]},"callee":null,"method_name":"keyOf","argument_types":["T"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@30:15"},"31:5":{"kind":"call","span":{"start":[31,5],"end":[31,31],"bytes":[901,927]},"callee":null,"method_name":"push","receiver_expr":"(out[k] ??= [])","receiver_type":"T[]","argument_types":["T"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@31:5"}},"callables":{"keyOf":{"id":"can://slim/typescript/src/util.ts/classify/keyOf","kind":"function","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"name":"keyOf","signature":"src/util.classify.keyOf","comments":[],"decorators":[],"parameters":[{"name":"item","type":"T","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":25,"end_line":25,"start_column":18,"end_column":25,"id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,31],"bytes":[776,795]},"callee":null,"method_name":"charAt","receiver_expr":"item.name","receiver_type":"string","argument_types":["0"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:12"}},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"54886cff7e11ccadc987571f508b2aef2f324b14e63d8ad52100499851d130fa"}},"call_graph":[],"param_in":[],"param_out":[],"artifacts":{"package.json":{"id":"can://slim/artifact/package.json","kind":"artifact","path":"package.json","format":"json","roles":["dependency-manifest","tool-config"],"size_bytes":88,"sha256":"277f174033b3f17dcd3ba9a550b53289624f034606303cef18a3f84ab7156c67","source":"{\n \"name\": \"sample-app\",\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"private\": true\n}\n","extraction":"none","config_keys":[]},"tsconfig.json":{"id":"can://slim/artifact/tsconfig.json","kind":"artifact","path":"tsconfig.json","format":"json","roles":["tool-config"],"size_bytes":289,"sha256":"72f24fc616456ab556dd8e7c886264214cb344547b32b972eb476467af0a9cab","source":"{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"experimentalDecorators\": true,\n \"emitDecoratorMetadata\": true\n },\n \"include\": [\"src/**/*.ts\"]\n}\n","extraction":"full","config_keys":[{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.target","key":"compilerOptions.target","namespace":"json","value":"ES2022","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.module","key":"compilerOptions.module","namespace":"json","value":"ESNext","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.moduleResolution","key":"compilerOptions.moduleResolution","namespace":"json","value":"bundler","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.strict","key":"compilerOptions.strict","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.esModuleInterop","key":"compilerOptions.esModuleInterop","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.skipLibCheck","key":"compilerOptions.skipLibCheck","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.experimentalDecorators","key":"compilerOptions.experimentalDecorators","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.emitDecoratorMetadata","key":"compilerOptions.emitDecoratorMetadata","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/include.0","key":"include.0","namespace":"json","value":"src/**/*.ts","references":[]}]}},"dependencies":[],"unresolved_imports":[],"config_uses":[],"config_reads":[],"entrypoint_report":{"frameworks_detected":[],"rulesets":["shipped"],"unresolved":{"Get":2,"Controller":1},"errors":[]}}} \ No newline at end of file +{"schema_version":"2.0.0","language":"typescript","max_level":1,"analyzer":{"name":"codeanalyzer-typescript","version":"1.6.0"},"application":{"id":"can://slim","kind":"application","symbol_table":{"src/controllers.ts":{"id":"can://slim/typescript/src/controllers.ts","kind":"module","span":{"start":[1,1],"end":[29,1],"bytes":[0,699]},"source":"import { UserService } from \"./services\";\n\n// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.\nfunction Controller(prefix: string): ClassDecorator {\n return () => undefined;\n}\nfunction Get(path: string): MethodDecorator {\n return () => undefined;\n}\nfunction Param(name: string): ParameterDecorator {\n return () => undefined;\n}\n\n@Controller(\"/users\")\nexport class UserController {\n constructor(private readonly service: UserService) {}\n\n @Get(\"/:id\")\n show(@Param(\"id\") id: string): string {\n const user = this.service.create(id);\n return user.describe();\n }\n\n @Get(\"/\")\n list(): string[] {\n return this.service.describeAll();\n }\n}\n","imports":[{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":42,"resolved_module":"src/services.ts"}],"exports":[],"comments":[{"content":"// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.","is_docstring":false,"start_line":3,"end_line":3,"start_column":1,"end_column":101}],"types":{"UserController":{"id":"can://slim/typescript/src/controllers.ts/UserController","kind":"class","span":{"start":[14,1],"end":[28,2],"bytes":[380,698]},"name":"UserController","signature":"src/controllers.UserController","comments":[],"decorators":[{"name":"Controller","positional_arguments":["\"/users\""],"keyword_arguments":{},"start_line":14,"end_line":14,"start_column":1,"end_column":22}],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"show":{"id":"can://slim/typescript/src/controllers.ts/UserController/show","kind":"method","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"name":"show","signature":"src/controllers.UserController.show","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/:id\""],"keyword_arguments":{},"start_line":18,"end_line":18,"start_column":3,"end_column":15}],"parameters":[{"name":"id","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[{"name":"Param","positional_arguments":["\"id\""],"keyword_arguments":{},"start_line":19,"end_line":19,"start_column":8,"end_column":20}],"start_line":19,"end_line":19,"start_column":8,"end_column":31,"id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"20:18":{"kind":"call","span":{"start":[20,18],"end":[20,41],"bytes":[563,586]},"callee":null,"method_name":"create","receiver_expr":"this.service","receiver_type":"UserService","argument_types":["string"],"type_arguments":[],"return_type":"import(\"./models\").User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:18"},"21:12":{"kind":"call","span":{"start":[21,12],"end":[21,27],"bytes":[599,614]},"callee":null,"method_name":"describe","receiver_expr":"user","receiver_type":"import(\"./models\").User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:12"},"19:9":{"kind":"call","span":{"start":[19,9],"end":[19,20],"bytes":[512,523]},"callee":null,"method_name":"Param","argument_types":["\"id\""],"type_arguments":[],"return_type":"ParameterDecorator","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@19:9"}},"entrypoints":[],"is_entrypoint":false},"list":{"id":"can://slim/typescript/src/controllers.ts/UserController/list","kind":"method","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"name":"list","signature":"src/controllers.UserController.list","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/\""],"keyword_arguments":{},"start_line":24,"end_line":24,"start_column":3,"end_column":12}],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,38],"bytes":[665,691]},"callee":null,"method_name":"describeAll","receiver_expr":"this.service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:12"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/controllers.ts/UserController/constructor","kind":"constructor","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"name":"constructor","signature":"src/controllers.UserController.constructor","comments":[],"decorators":[],"parameters":[{"name":"service","type":"UserService","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":16,"end_line":16,"start_column":15,"end_column":52,"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"service":{"id":"can://slim/typescript/src/controllers.ts/UserController/service","kind":"field","name":"service","type":"UserService","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"Controller":{"id":"can://slim/typescript/src/controllers.ts/Controller","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"name":"Controller","signature":"src/controllers.Controller","comments":[],"decorators":[],"parameters":[{"name":"prefix","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":21,"end_column":35,"id":"can://slim/typescript/src/controllers.ts/Controller@formal_in:0"}],"type_parameters":[],"return_type":"ClassDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"arrow","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"name":"(anonymous)","signature":"src/controllers.Controller.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"Get":{"id":"can://slim/typescript/src/controllers.ts/Get","kind":"function","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"name":"Get","signature":"src/controllers.Get","comments":[],"decorators":[],"parameters":[{"name":"path","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":14,"end_column":26,"id":"can://slim/typescript/src/controllers.ts/Get@formal_in:0"}],"type_parameters":[],"return_type":"MethodDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"arrow","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"name":"(anonymous)","signature":"src/controllers.Get.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"Param":{"id":"can://slim/typescript/src/controllers.ts/Param","kind":"function","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"name":"Param","signature":"src/controllers.Param","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":10,"end_line":10,"start_column":16,"end_column":28,"id":"can://slim/typescript/src/controllers.ts/Param@formal_in:0"}],"type_parameters":[],"return_type":"ParameterDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"arrow","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"name":"(anonymous)","signature":"src/controllers.Param.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d42b8f615d51575e3436409b9fce70862182b6071da40471b4be9b95f7c9ee4c"},"src/index.ts":{"id":"can://slim/typescript/src/index.ts","kind":"module","span":{"start":[1,1],"end":[26,1],"bytes":[0,742]},"source":"import { UserController } from \"./controllers\";\nimport { Robot, Role, User } from \"./models\";\nimport { UserService, announce } from \"./services\";\nimport { StringUtil } from \"./util\";\n\nexport function main(): void {\n const service = new UserService(100);\n service.create(\"Ada\", Role.Admin);\n service.createGuest();\n\n const controller = new UserController(service);\n controller.list();\n controller.show(\"42\");\n\n // interface-typed dispatch — RTA should expand announce -> {User,Robot}.describe\n announce(new User(1, \"Ada\", Role.Admin));\n announce(new Robot(\"r2d2\"));\n\n const slug = StringUtil.repeat(\"hello world\", 2);\n const builder = new StringUtil.Builder();\n builder.add(\"a\").add(\"b\").build();\n console.log(slug);\n}\n\nmain();\n","imports":[{"module":"./controllers","name":"UserController","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":48,"resolved_module":"src/controllers.ts"},{"module":"./models","name":"Robot","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./services","name":"announce","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./util","name":"StringUtil","is_type_only":false,"import_kind":"named","start_line":4,"end_line":4,"start_column":1,"end_column":37,"resolved_module":"src/util.ts"}],"exports":[],"comments":[],"types":{},"functions":{"main":{"id":"can://slim/typescript/src/index.ts/main","kind":"function","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"name":"main","signature":"src/index.main","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"void","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"7:19":{"kind":"call","span":{"start":[7,19],"end":[7,39],"bytes":[233,253]},"callee":null,"method_name":"UserService","argument_types":["100"],"type_arguments":[],"return_type":"UserService","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@7:19"},"8:3":{"kind":"call","span":{"start":[8,3],"end":[8,36],"bytes":[257,290]},"callee":null,"method_name":"create","receiver_expr":"service","receiver_type":"UserService","argument_types":["\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@8:3"},"9:3":{"kind":"call","span":{"start":[9,3],"end":[9,24],"bytes":[294,315]},"callee":null,"method_name":"createGuest","receiver_expr":"service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@9:3"},"11:22":{"kind":"call","span":{"start":[11,22],"end":[11,49],"bytes":[339,366]},"callee":null,"method_name":"UserController","argument_types":["UserService"],"type_arguments":[],"return_type":"UserController","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@11:22"},"12:3":{"kind":"call","span":{"start":[12,3],"end":[12,20],"bytes":[370,387]},"callee":null,"method_name":"list","receiver_expr":"controller","receiver_type":"UserController","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@12:3"},"13:3":{"kind":"call","span":{"start":[13,3],"end":[13,24],"bytes":[391,412]},"callee":null,"method_name":"show","receiver_expr":"controller","receiver_type":"UserController","argument_types":["\"42\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@13:3"},"16:3":{"kind":"call","span":{"start":[16,3],"end":[16,43],"bytes":[503,543]},"callee":null,"method_name":"announce","argument_types":["User"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:3"},"16:12":{"kind":"call","span":{"start":[16,12],"end":[16,42],"bytes":[512,542]},"callee":null,"method_name":"User","argument_types":["1","\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:12"},"17:3":{"kind":"call","span":{"start":[17,3],"end":[17,30],"bytes":[547,574]},"callee":null,"method_name":"announce","argument_types":["Robot"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:3"},"17:12":{"kind":"call","span":{"start":[17,12],"end":[17,29],"bytes":[556,573]},"callee":null,"method_name":"Robot","argument_types":["\"r2d2\""],"type_arguments":[],"return_type":"Robot","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:12"},"19:16":{"kind":"call","span":{"start":[19,16],"end":[19,51],"bytes":[592,627]},"callee":null,"method_name":"repeat","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":["\"hello world\"","2"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@19:16"},"20:19":{"kind":"call","span":{"start":[20,19],"end":[20,43],"bytes":[647,671]},"callee":null,"method_name":"Builder","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":[],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@20:19"},"21:3":{"kind":"call","span":{"start":[21,3],"end":[21,36],"bytes":[675,708]},"callee":null,"method_name":"build","receiver_expr":"builder.add(\"a\").add(\"b\")","receiver_type":"StringUtil.Builder","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3"},"21:3/2":{"kind":"call","span":{"start":[21,3],"end":[21,28],"bytes":[675,700]},"callee":null,"method_name":"add","receiver_expr":"builder.add(\"a\")","receiver_type":"StringUtil.Builder","argument_types":["\"b\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/2"},"21:3/3":{"kind":"call","span":{"start":[21,3],"end":[21,19],"bytes":[675,691]},"callee":null,"method_name":"add","receiver_expr":"builder","receiver_type":"StringUtil.Builder","argument_types":["\"a\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/3"},"22:3":{"kind":"call","span":{"start":[22,3],"end":[22,20],"bytes":[712,729]},"callee":null,"method_name":"log","receiver_expr":"console","receiver_type":"Console","argument_types":["string"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@22:3"}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"6de6f6ff5a01a5c7c750a93d5e10bae7b15817f386421f45c7527cfb7259d9b3"},"src/models.ts":{"id":"can://slim/typescript/src/models.ts","kind":"module","span":{"start":[1,1],"end":[65,1],"bytes":[0,1237]},"source":"/** Domain models for the sample app. */\n\nexport interface Identifiable {\n readonly id: T;\n}\n\nexport interface Named {\n name: string;\n describe(): string;\n}\n\nexport type UserId = string | number;\n\nexport enum Role {\n Admin = \"admin\",\n Member = \"member\",\n Guest = \"guest\",\n}\n\nexport const enum Flag {\n None = 0,\n Active = 1,\n}\n\n/** A user of the system. */\nexport abstract class Entity implements Identifiable {\n constructor(public readonly id: ID) {}\n abstract describe(): string;\n}\n\nexport class User extends Entity implements Named {\n private loginCount = 0;\n static instances = 0;\n\n constructor(\n id: UserId,\n public name: string,\n private role: Role = Role.Member,\n ) {\n super(id);\n User.instances++;\n }\n\n get isAdmin(): boolean {\n return this.role === Role.Admin;\n }\n\n describe(): string {\n return `${this.name} (${this.role})`;\n }\n\n async recordLogin(): Promise {\n this.loginCount += 1;\n return this.loginCount;\n }\n}\n\n/** A second, unrelated implementer of Named — drives RTA subtype expansion. */\nexport class Robot implements Named {\n constructor(public name: string) {}\n describe(): string {\n return `robot:${this.name}`;\n }\n}\n","imports":[],"exports":[],"comments":[{"content":"/** Domain models for the sample app. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41},{"content":"/** A user of the system. */","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29},{"content":"/** A second, unrelated implementer of Named — drives RTA subtype expansion. */","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"types":{"Entity":{"id":"can://slim/typescript/src/models.ts/Entity","kind":"class","span":{"start":[26,1],"end":[29,2],"bytes":[376,521]},"name":"Entity","signature":"src/models.Entity","comments":[{"content":"A user of the system.","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29}],"decorators":[],"base_classes":["src/models.Identifiable"],"implements_types":["src/models.Identifiable"],"type_parameters":[{"name":"ID","default":"string"}],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Entity/describe","kind":"method","span":{"start":[28,3],"end":[28,31],"bytes":[491,519]},"name":"describe","signature":"src/models.Entity.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":true,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[{"parameters":[],"return_type":"string","type_parameters":[],"start_line":28,"end_line":28}],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Entity/constructor","kind":"constructor","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"name":"constructor","signature":"src/models.Entity.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"ID","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"public","decorators":[],"start_line":27,"end_line":27,"start_column":15,"end_column":37,"id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Entity/id","kind":"field","name":"id","type":"ID","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":true,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Identifiable"],"entrypoints":[],"is_entrypoint":false},"User":{"id":"can://slim/typescript/src/models.ts/User","kind":"class","span":{"start":[31,1],"end":[56,2],"bytes":[523,1015]},"name":"User","signature":"src/models.User","comments":[],"decorators":[],"base_classes":["src/models.Entity","src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/User/describe","kind":"method","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"name":"describe","signature":"src/models.User.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"recordLogin":{"id":"can://slim/typescript/src/models.ts/User/recordLogin","kind":"method","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"name":"recordLogin","signature":"src/models.User.recordLogin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/User/constructor","kind":"constructor","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"name":"constructor","signature":"src/models.User.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"UserId","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":36,"end_line":36,"start_column":5,"end_column":15,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0"},{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":37,"end_line":37,"start_column":5,"end_column":24,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"accessibility":"private","decorators":[],"start_line":38,"end_line":38,"start_column":5,"end_column":37,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"40:5":{"kind":"call","span":{"start":[40,5],"end":[40,14],"bytes":[738,747]},"callee":null,"method_name":"super","argument_types":["UserId"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/models.ts/User/constructor@40:5"}},"entrypoints":[],"is_entrypoint":false},"isAdmin#get":{"id":"can://slim/typescript/src/models.ts/User/isAdmin","kind":"getter","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"name":"isAdmin","signature":"src/models.User.isAdmin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"boolean","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"accessor_kind":"getter","overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"loginCount":{"id":"can://slim/typescript/src/models.ts/User/loginCount","kind":"field","span":{"start":[32,3],"end":[32,26],"bytes":[585,608]},"name":"loginCount","type":"number","comments":[],"decorators":[],"initializer":"0","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"instances":{"id":"can://slim/typescript/src/models.ts/User/instances","kind":"field","span":{"start":[33,3],"end":[33,24],"bytes":[611,632]},"name":"instances","type":"number","comments":[],"decorators":[],"initializer":"0","is_static":true,"is_readonly":false,"is_optional":false,"is_abstract":false},"name":{"id":"can://slim/typescript/src/models.ts/User/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"role":{"id":"can://slim/typescript/src/models.ts/User/role","kind":"field","name":"role","type":"Role","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":false,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"extends_ids":["can://slim/typescript/src/models.ts/Entity"],"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Robot":{"id":"can://slim/typescript/src/models.ts/Robot","kind":"class","span":{"start":[59,1],"end":[64,2],"bytes":[1099,1236]},"name":"Robot","signature":"src/models.Robot","comments":[{"content":"A second, unrelated implementer of Named — drives RTA subtype expansion.","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"decorators":[],"base_classes":["src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Robot/describe","kind":"method","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"name":"describe","signature":"src/models.Robot.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Robot/constructor","kind":"constructor","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"name":"constructor","signature":"src/models.Robot.constructor","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":60,"end_line":60,"start_column":15,"end_column":34,"id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Robot/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Identifiable":{"id":"can://slim/typescript/src/models.ts/Identifiable","kind":"interface","span":{"start":[3,1],"end":[5,2],"bytes":[42,105]},"name":"Identifiable","signature":"src/models.Identifiable","comments":[{"content":"Domain models for the sample app.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41}],"base_classes":[],"type_parameters":[{"name":"T","default":"string"}],"callables":{},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Identifiable/id","kind":"field","span":{"start":[4,3],"end":[4,18],"bytes":[88,103]},"name":"id","type":"T","comments":[],"decorators":[],"is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Named":{"id":"can://slim/typescript/src/models.ts/Named","kind":"interface","span":{"start":[7,1],"end":[10,2],"bytes":[107,171]},"name":"Named","signature":"src/models.Named","comments":[],"base_classes":[],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Named/describe","kind":"method","span":{"start":[9,3],"end":[9,22],"bytes":[150,169]},"name":"describe","signature":"src/models.Named.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Named/name","kind":"field","span":{"start":[8,3],"end":[8,16],"bytes":[134,147]},"name":"name","type":"string","comments":[],"decorators":[],"is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Role":{"id":"can://slim/typescript/src/models.ts/Role","kind":"enum","span":{"start":[14,1],"end":[18,2],"bytes":[212,291]},"name":"Role","signature":"src/models.Role","comments":[],"fields":{"Admin":{"id":"can://slim/typescript/src/models.ts/Role/Admin","kind":"field","span":{"start":[15,3],"end":[15,18],"bytes":[233,248]},"name":"Admin","value":"admin"},"Member":{"id":"can://slim/typescript/src/models.ts/Role/Member","kind":"field","span":{"start":[16,3],"end":[16,20],"bytes":[252,269]},"name":"Member","value":"member"},"Guest":{"id":"can://slim/typescript/src/models.ts/Role/Guest","kind":"field","span":{"start":[17,3],"end":[17,18],"bytes":[273,288]},"name":"Guest","value":"guest"}},"is_const":false,"is_exported":true,"is_ambient":false},"Flag":{"id":"can://slim/typescript/src/models.ts/Flag","kind":"enum","span":{"start":[20,1],"end":[23,2],"bytes":[293,345]},"name":"Flag","signature":"src/models.Flag","comments":[],"fields":{"None":{"id":"can://slim/typescript/src/models.ts/Flag/None","kind":"field","span":{"start":[21,3],"end":[21,11],"bytes":[320,328]},"name":"None","value":"0"},"Active":{"id":"can://slim/typescript/src/models.ts/Flag/Active","kind":"field","span":{"start":[22,3],"end":[22,13],"bytes":[332,342]},"name":"Active","value":"1"}},"is_const":true,"is_exported":true,"is_ambient":false},"UserId":{"id":"can://slim/typescript/src/models.ts/UserId","kind":"type_alias","span":{"start":[12,1],"end":[12,38],"bytes":[173,210]},"name":"UserId","signature":"src/models.UserId","comments":[],"aliased_type":"string | number","type_parameters":[],"is_exported":true,"is_ambient":false}},"functions":{},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d39ff571ccfda4b7c46923586b6b94d0e818a51be966f1ba40305650fd0ffc91"},"src/services.ts":{"id":"can://slim/typescript/src/services.ts","kind":"module","span":{"start":[1,1],"end":[48,1],"bytes":[0,1240]},"source":"import { type Named, Role, User, type UserId } from \"./models\";\n\n/** Pure helper — top-level function. */\nexport function makeGuestName(seed: number): string {\n return `guest-${seed}`;\n}\n\n/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */\nexport function announce(thing: Named): string {\n return thing.describe();\n}\n\n/** Arrow function bound to a const (function_expression-style callable). */\nexport const nextId = (n: number): UserId => n + 1;\n\nexport class UserService {\n private users: User[] = [];\n\n constructor(private readonly startId: number = 0) {}\n\n create(name: string, role: Role = Role.Member): User {\n const id = nextId(this.users.length + this.startId);\n const user = new User(id, name, role);\n this.users.push(user);\n return user;\n }\n\n createGuest(): User {\n const name = makeGuestName(this.users.length);\n return this.create(name, Role.Guest);\n }\n\n describeAll(): string[] {\n return this.users.map((u) => u.describe());\n }\n\n async loginAll(): Promise {\n let total = 0;\n for (const u of this.users) {\n total += await u.recordLogin();\n }\n return total;\n }\n}\n","imports":[{"module":"./models","name":"Named","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"UserId","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"}],"exports":[],"comments":[{"content":"/** Pure helper — top-level function. */","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41},{"content":"/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4},{"content":"/** Arrow function bound to a const (function_expression-style callable). */","is_docstring":true,"start_line":16,"end_line":16,"start_column":1,"end_column":77}],"types":{"UserService":{"id":"can://slim/typescript/src/services.ts/UserService","kind":"class","span":{"start":[19,1],"end":[47,2],"bytes":[558,1239]},"name":"UserService","signature":"src/services.UserService","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"create":{"id":"can://slim/typescript/src/services.ts/UserService/create","kind":"method","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"name":"create","signature":"src/services.UserService.create","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":10,"end_column":22,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":24,"end_column":48,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1"}],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"25:16":{"kind":"call","span":{"start":[25,16],"end":[25,56],"bytes":[744,784]},"callee":null,"method_name":"nextId","argument_types":["number"],"type_arguments":[],"return_type":"UserId","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@25:16"},"26:18":{"kind":"call","span":{"start":[26,18],"end":[26,42],"bytes":[803,827]},"callee":null,"method_name":"User","argument_types":["UserId","string","Role"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@26:18"},"27:5":{"kind":"call","span":{"start":[27,5],"end":[27,26],"bytes":[833,854]},"callee":null,"method_name":"push","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["User"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@27:5"}},"entrypoints":[],"is_entrypoint":false},"createGuest":{"id":"can://slim/typescript/src/services.ts/UserService/createGuest","kind":"method","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"name":"createGuest","signature":"src/services.UserService.createGuest","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"32:18":{"kind":"call","span":{"start":[32,18],"end":[32,50],"bytes":[919,951]},"callee":null,"method_name":"makeGuestName","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:18"},"33:12":{"kind":"call","span":{"start":[33,12],"end":[33,41],"bytes":[964,993]},"callee":null,"method_name":"create","receiver_expr":"this","receiver_type":"this","argument_types":["string","Role.Guest"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:12"}},"entrypoints":[],"is_entrypoint":false},"describeAll":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll","kind":"method","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"name":"describeAll","signature":"src/services.UserService.describeAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:12":{"kind":"call","span":{"start":[37,12],"end":[37,47],"bytes":[1039,1074]},"callee":null,"method_name":"map","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["(u: User) => string"],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:12"}},"callables":{"":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"arrow","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"name":"(anonymous)","signature":"src/services.UserService.describeAll.","comments":[],"decorators":[],"parameters":[{"name":"u","type":"User","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":37,"end_line":37,"start_column":28,"end_column":29,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:34":{"kind":"call","span":{"start":[37,34],"end":[37,46],"bytes":[1061,1073]},"callee":null,"method_name":"describe","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34"}},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"loginAll":{"id":"can://slim/typescript/src/services.ts/UserService/loginAll","kind":"method","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"name":"loginAll","signature":"src/services.UserService.loginAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"43:22":{"kind":"call","span":{"start":[43,22],"end":[43,37],"bytes":[1193,1208]},"callee":null,"method_name":"recordLogin","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"Promise","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:22"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/services.ts/UserService/constructor","kind":"constructor","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"name":"constructor","signature":"src/services.UserService.constructor","comments":[],"decorators":[],"parameters":[{"name":"startId","type":"number","default_value":"0","is_optional":true,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":22,"end_line":22,"start_column":15,"end_column":51,"id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"users":{"id":"can://slim/typescript/src/services.ts/UserService/users","kind":"field","span":{"start":[20,3],"end":[20,30],"bytes":[587,614]},"name":"users","type":"User[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"startId":{"id":"can://slim/typescript/src/services.ts/UserService/startId","kind":"field","name":"startId","type":"number","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"makeGuestName":{"id":"can://slim/typescript/src/services.ts/makeGuestName","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"name":"makeGuestName","signature":"src/services.makeGuestName","comments":[{"content":"Pure helper — top-level function.","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41}],"decorators":[],"parameters":[{"name":"seed","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":31,"end_column":43,"id":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"announce":{"id":"can://slim/typescript/src/services.ts/announce","kind":"function","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"name":"announce","signature":"src/services.announce","comments":[{"content":"Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\nconcrete implementer of Named (User, Robot, ...).","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4}],"decorators":[],"parameters":[{"name":"thing","type":"Named","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":12,"end_line":12,"start_column":26,"end_column":38,"id":"can://slim/typescript/src/services.ts/announce@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"13:10":{"kind":"call","span":{"start":[13,10],"end":[13,26],"bytes":[407,423]},"callee":null,"method_name":"describe","receiver_expr":"thing","receiver_type":"Named","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/announce@13:10"}},"entrypoints":[],"is_entrypoint":false},"nextId":{"id":"can://slim/typescript/src/services.ts/nextId","kind":"arrow","span":{"start":[17,14],"end":[17,51],"bytes":[518,555]},"name":"nextId","signature":"src/services.nextId","comments":[],"decorators":[],"parameters":[{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":17,"end_line":17,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/services.ts/nextId@formal_in:0"}],"type_parameters":[],"return_type":"UserId","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"1bda3666dab48f8e686fb8ffc2143f2e422af62be46698053cfeea4184b55617"},"src/util.ts":{"id":"can://slim/typescript/src/util.ts","kind":"module","span":{"start":[1,1],"end":[35,1],"bytes":[0,949]},"source":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */\nexport namespace StringUtil {\n export function repeat(s: string, n: number): string {\n return slug(s).repeat(n);\n }\n\n export function slug(s: string): string {\n return s.toLowerCase().replace(/\\s+/g, \"-\");\n }\n\n export class Builder {\n private parts: string[] = [];\n add(part: string): this {\n this.parts.push(slug(part));\n return this;\n }\n build(): string {\n return this.parts.join(\"/\");\n }\n }\n}\n\n/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */\nexport function classify(items: T[]): Record {\n function keyOf(item: T): string {\n return item.name.charAt(0);\n }\n const out: Record = {};\n for (const item of items) {\n const k = keyOf(item);\n (out[k] ??= []).push(item);\n }\n return out;\n}\n","imports":[],"exports":[],"comments":[{"content":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106},{"content":"/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"types":{"StringUtil":{"id":"can://slim/typescript/src/util.ts/StringUtil","kind":"namespace","span":{"start":[2,1],"end":[21,2],"bytes":[106,543]},"name":"StringUtil","signature":"src/util.StringUtil","comments":[{"content":"A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106}],"types":{"Builder":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder","kind":"class","span":{"start":[11,3],"end":[20,4],"bytes":[328,541]},"name":"Builder","signature":"src/util.StringUtil.Builder","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"add":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","kind":"method","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"name":"add","signature":"src/util.StringUtil.Builder.add","comments":[],"decorators":[],"parameters":[{"name":"part","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":13,"end_line":13,"start_column":9,"end_column":21,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0"}],"type_parameters":[],"return_type":"this","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"14:7":{"kind":"call","span":{"start":[14,7],"end":[14,34],"bytes":[421,448]},"callee":null,"method_name":"push","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["string"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7"},"14:23":{"kind":"call","span":{"start":[14,23],"end":[14,33],"bytes":[437,447]},"callee":null,"method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:23"}},"entrypoints":[],"is_entrypoint":false},"build":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","kind":"method","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"name":"build","signature":"src/util.StringUtil.Builder.build","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"18:14":{"kind":"call","span":{"start":[18,14],"end":[18,34],"bytes":[510,530]},"callee":null,"method_name":"join","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["\"/\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:14"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","kind":"constructor","span":{"start":[0,0],"end":[0,0],"bytes":[0,0]},"name":"constructor","signature":"src/util.StringUtil.Builder.constructor","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":true,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"parts":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/parts","kind":"field","span":{"start":[12,5],"end":[12,34],"bytes":[355,384]},"name":"parts","type":"string[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"repeat":{"id":"can://slim/typescript/src/util.ts/StringUtil/repeat","kind":"function","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"name":"repeat","signature":"src/util.StringUtil.repeat","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":26,"end_column":35,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0"},{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":37,"end_column":46,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"4:12":{"kind":"call","span":{"start":[4,12],"end":[4,29],"bytes":[204,221]},"callee":null,"method_name":"repeat","receiver_expr":"slug(s)","receiver_type":"string","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12"},"4:12/2":{"kind":"call","span":{"start":[4,12],"end":[4,19],"bytes":[204,211]},"callee":null,"method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12/2"}},"entrypoints":[],"is_entrypoint":false},"slug":{"id":"can://slim/typescript/src/util.ts/StringUtil/slug","kind":"function","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"name":"slug","signature":"src/util.StringUtil.slug","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"8:12":{"kind":"call","span":{"start":[8,12],"end":[8,48],"bytes":[283,319]},"callee":null,"method_name":"replace","receiver_expr":"s.toLowerCase()","receiver_type":"string","argument_types":["RegExp","\"-\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12"},"8:12/2":{"kind":"call","span":{"start":[8,12],"end":[8,27],"bytes":[283,298]},"callee":null,"method_name":"toLowerCase","receiver_expr":"s","receiver_type":"string","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12/2"}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_exported":true,"is_ambient":false}},"functions":{"classify":{"id":"can://slim/typescript/src/util.ts/classify","kind":"function","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"name":"classify","signature":"src/util.classify","comments":[{"content":"Generic top-level function with a nested helper, to exercise inner_callables + generics.","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"decorators":[],"parameters":[{"name":"items","type":"T[]","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":54,"end_column":64,"id":"can://slim/typescript/src/util.ts/classify@formal_in:0"}],"type_parameters":[{"name":"T","constraint":"{ name: string }"}],"return_type":"Record","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"30:15":{"kind":"call","span":{"start":[30,15],"end":[30,26],"bytes":[884,895]},"callee":null,"method_name":"keyOf","argument_types":["T"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@30:15"},"31:5":{"kind":"call","span":{"start":[31,5],"end":[31,31],"bytes":[901,927]},"callee":null,"method_name":"push","receiver_expr":"(out[k] ??= [])","receiver_type":"T[]","argument_types":["T"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@31:5"}},"callables":{"keyOf":{"id":"can://slim/typescript/src/util.ts/classify/keyOf","kind":"function","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"name":"keyOf","signature":"src/util.classify.keyOf","comments":[],"decorators":[],"parameters":[{"name":"item","type":"T","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":25,"end_line":25,"start_column":18,"end_column":25,"id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,31],"bytes":[776,795]},"callee":null,"method_name":"charAt","receiver_expr":"item.name","receiver_type":"string","argument_types":["0"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:12"}},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"54886cff7e11ccadc987571f508b2aef2f324b14e63d8ad52100499851d130fa"}},"call_graph":[],"param_in":[],"param_out":[],"artifacts":{"package.json":{"id":"can://slim/artifact/package.json","kind":"artifact","path":"package.json","format":"json","roles":["dependency-manifest","tool-config"],"size_bytes":88,"sha256":"277f174033b3f17dcd3ba9a550b53289624f034606303cef18a3f84ab7156c67","source":"{\n \"name\": \"sample-app\",\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"private\": true\n}\n","extraction":"none","config_keys":[]},"tsconfig.json":{"id":"can://slim/artifact/tsconfig.json","kind":"artifact","path":"tsconfig.json","format":"json","roles":["tool-config"],"size_bytes":289,"sha256":"72f24fc616456ab556dd8e7c886264214cb344547b32b972eb476467af0a9cab","source":"{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"experimentalDecorators\": true,\n \"emitDecoratorMetadata\": true\n },\n \"include\": [\"src/**/*.ts\"]\n}\n","extraction":"full","config_keys":[{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.target","key":"compilerOptions.target","namespace":"json","value":"ES2022","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.module","key":"compilerOptions.module","namespace":"json","value":"ESNext","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.moduleResolution","key":"compilerOptions.moduleResolution","namespace":"json","value":"bundler","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.strict","key":"compilerOptions.strict","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.esModuleInterop","key":"compilerOptions.esModuleInterop","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.skipLibCheck","key":"compilerOptions.skipLibCheck","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.experimentalDecorators","key":"compilerOptions.experimentalDecorators","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.emitDecoratorMetadata","key":"compilerOptions.emitDecoratorMetadata","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/include.0","key":"include.0","namespace":"json","value":"src/**/*.ts","references":[]}]}},"dependencies":[],"unresolved_imports":[],"config_uses":[],"config_reads":[],"entrypoint_report":{"frameworks_detected":[],"rulesets":["shipped"],"unresolved":{"Get":2,"Controller":1},"errors":[]}}} \ No newline at end of file diff --git a/tests/resources/typescript/analysis_json/v2/a2/analysis.json b/tests/resources/typescript/analysis_json/v2/a2/analysis.json index 5d18a671..2c25b681 100644 --- a/tests/resources/typescript/analysis_json/v2/a2/analysis.json +++ b/tests/resources/typescript/analysis_json/v2/a2/analysis.json @@ -1 +1 @@ -{"schema_version":"2.0.0","language":"typescript","max_level":2,"analyzer":{"name":"codeanalyzer-typescript","version":"1.5.3"},"application":{"id":"can://slim","kind":"application","symbol_table":{"src/controllers.ts":{"id":"can://slim/typescript/src/controllers.ts","kind":"module","span":{"start":[1,1],"end":[29,1],"bytes":[0,699]},"source":"import { UserService } from \"./services\";\n\n// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.\nfunction Controller(prefix: string): ClassDecorator {\n return () => undefined;\n}\nfunction Get(path: string): MethodDecorator {\n return () => undefined;\n}\nfunction Param(name: string): ParameterDecorator {\n return () => undefined;\n}\n\n@Controller(\"/users\")\nexport class UserController {\n constructor(private readonly service: UserService) {}\n\n @Get(\"/:id\")\n show(@Param(\"id\") id: string): string {\n const user = this.service.create(id);\n return user.describe();\n }\n\n @Get(\"/\")\n list(): string[] {\n return this.service.describeAll();\n }\n}\n","imports":[{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":42,"resolved_module":"src/services.ts"}],"exports":[],"comments":[{"content":"// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.","is_docstring":false,"start_line":3,"end_line":3,"start_column":1,"end_column":101}],"types":{"UserController":{"id":"can://slim/typescript/src/controllers.ts/UserController","kind":"class","span":{"start":[14,1],"end":[28,2],"bytes":[380,698]},"name":"UserController","signature":"src/controllers.UserController","comments":[],"decorators":[{"name":"Controller","positional_arguments":["\"/users\""],"keyword_arguments":{},"start_line":14,"end_line":14,"start_column":1,"end_column":22}],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"show":{"id":"can://slim/typescript/src/controllers.ts/UserController/show","kind":"method","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"name":"show","signature":"src/controllers.UserController.show","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/:id\""],"keyword_arguments":{},"start_line":18,"end_line":18,"start_column":3,"end_column":15}],"parameters":[{"name":"id","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[{"name":"Param","positional_arguments":["\"id\""],"keyword_arguments":{},"start_line":19,"end_line":19,"start_column":8,"end_column":20}],"start_line":19,"end_line":19,"start_column":8,"end_column":31,"id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"20:18":{"kind":"call","span":{"start":[20,18],"end":[20,41],"bytes":[563,586]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this.service","receiver_type":"UserService","argument_types":["string"],"type_arguments":[],"return_type":"import(\"./models\").User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:18"},"21:12":{"kind":"call","span":{"start":[21,12],"end":[21,27],"bytes":[599,614]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"user","receiver_type":"import(\"./models\").User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:12"},"19:9":{"kind":"call","span":{"start":[19,9],"end":[19,20],"bytes":[512,523]},"callee":"can://slim/typescript/src/controllers.ts/Param","method_name":"Param","argument_types":["\"id\""],"type_arguments":[],"return_type":"ParameterDecorator","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@19:9"}},"entrypoints":[],"is_entrypoint":false},"list":{"id":"can://slim/typescript/src/controllers.ts/UserController/list","kind":"method","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"name":"list","signature":"src/controllers.UserController.list","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/\""],"keyword_arguments":{},"start_line":24,"end_line":24,"start_column":3,"end_column":12}],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,38],"bytes":[665,691]},"callee":"can://slim/typescript/src/services.ts/UserService/describeAll","method_name":"describeAll","receiver_expr":"this.service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:12"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/controllers.ts/UserController/constructor","kind":"constructor","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"name":"constructor","signature":"src/controllers.UserController.constructor","comments":[],"decorators":[],"parameters":[{"name":"service","type":"UserService","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":16,"end_line":16,"start_column":15,"end_column":52,"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"service":{"id":"can://slim/typescript/src/controllers.ts/UserController/service","kind":"field","name":"service","type":"UserService","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"Controller":{"id":"can://slim/typescript/src/controllers.ts/Controller","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"name":"Controller","signature":"src/controllers.Controller","comments":[],"decorators":[],"parameters":[{"name":"prefix","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":21,"end_column":35,"id":"can://slim/typescript/src/controllers.ts/Controller@formal_in:0"}],"type_parameters":[],"return_type":"ClassDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"arrow","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"name":"(anonymous)","signature":"src/controllers.Controller.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"Get":{"id":"can://slim/typescript/src/controllers.ts/Get","kind":"function","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"name":"Get","signature":"src/controllers.Get","comments":[],"decorators":[],"parameters":[{"name":"path","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":14,"end_column":26,"id":"can://slim/typescript/src/controllers.ts/Get@formal_in:0"}],"type_parameters":[],"return_type":"MethodDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"arrow","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"name":"(anonymous)","signature":"src/controllers.Get.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"Param":{"id":"can://slim/typescript/src/controllers.ts/Param","kind":"function","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"name":"Param","signature":"src/controllers.Param","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":10,"end_line":10,"start_column":16,"end_column":28,"id":"can://slim/typescript/src/controllers.ts/Param@formal_in:0"}],"type_parameters":[],"return_type":"ParameterDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"arrow","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"name":"(anonymous)","signature":"src/controllers.Param.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d42b8f615d51575e3436409b9fce70862182b6071da40471b4be9b95f7c9ee4c"},"src/index.ts":{"id":"can://slim/typescript/src/index.ts","kind":"module","span":{"start":[1,1],"end":[26,1],"bytes":[0,742]},"source":"import { UserController } from \"./controllers\";\nimport { Robot, Role, User } from \"./models\";\nimport { UserService, announce } from \"./services\";\nimport { StringUtil } from \"./util\";\n\nexport function main(): void {\n const service = new UserService(100);\n service.create(\"Ada\", Role.Admin);\n service.createGuest();\n\n const controller = new UserController(service);\n controller.list();\n controller.show(\"42\");\n\n // interface-typed dispatch — RTA should expand announce -> {User,Robot}.describe\n announce(new User(1, \"Ada\", Role.Admin));\n announce(new Robot(\"r2d2\"));\n\n const slug = StringUtil.repeat(\"hello world\", 2);\n const builder = new StringUtil.Builder();\n builder.add(\"a\").add(\"b\").build();\n console.log(slug);\n}\n\nmain();\n","imports":[{"module":"./controllers","name":"UserController","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":48,"resolved_module":"src/controllers.ts"},{"module":"./models","name":"Robot","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./services","name":"announce","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./util","name":"StringUtil","is_type_only":false,"import_kind":"named","start_line":4,"end_line":4,"start_column":1,"end_column":37,"resolved_module":"src/util.ts"}],"exports":[],"comments":[],"types":{},"functions":{"main":{"id":"can://slim/typescript/src/index.ts/main","kind":"function","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"name":"main","signature":"src/index.main","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"void","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"7:19":{"kind":"call","span":{"start":[7,19],"end":[7,39],"bytes":[233,253]},"callee":"can://slim/typescript/src/services.ts/UserService/constructor","method_name":"UserService","argument_types":["100"],"type_arguments":[],"return_type":"UserService","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@7:19"},"8:3":{"kind":"call","span":{"start":[8,3],"end":[8,36],"bytes":[257,290]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"service","receiver_type":"UserService","argument_types":["\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@8:3"},"9:3":{"kind":"call","span":{"start":[9,3],"end":[9,24],"bytes":[294,315]},"callee":"can://slim/typescript/src/services.ts/UserService/createGuest","method_name":"createGuest","receiver_expr":"service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@9:3"},"11:22":{"kind":"call","span":{"start":[11,22],"end":[11,49],"bytes":[339,366]},"callee":"can://slim/typescript/src/controllers.ts/UserController/constructor","method_name":"UserController","argument_types":["UserService"],"type_arguments":[],"return_type":"UserController","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@11:22"},"12:3":{"kind":"call","span":{"start":[12,3],"end":[12,20],"bytes":[370,387]},"callee":"can://slim/typescript/src/controllers.ts/UserController/list","method_name":"list","receiver_expr":"controller","receiver_type":"UserController","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@12:3"},"13:3":{"kind":"call","span":{"start":[13,3],"end":[13,24],"bytes":[391,412]},"callee":"can://slim/typescript/src/controllers.ts/UserController/show","method_name":"show","receiver_expr":"controller","receiver_type":"UserController","argument_types":["\"42\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@13:3"},"16:3":{"kind":"call","span":{"start":[16,3],"end":[16,43],"bytes":[503,543]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["User"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:3"},"16:12":{"kind":"call","span":{"start":[16,12],"end":[16,42],"bytes":[512,542]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["1","\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:12"},"17:3":{"kind":"call","span":{"start":[17,3],"end":[17,30],"bytes":[547,574]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["Robot"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:3"},"17:12":{"kind":"call","span":{"start":[17,12],"end":[17,29],"bytes":[556,573]},"callee":"can://slim/typescript/src/models.ts/Robot/constructor","method_name":"Robot","argument_types":["\"r2d2\""],"type_arguments":[],"return_type":"Robot","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:12"},"19:16":{"kind":"call","span":{"start":[19,16],"end":[19,51],"bytes":[592,627]},"callee":"can://slim/typescript/src/util.ts/StringUtil/repeat","method_name":"repeat","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":["\"hello world\"","2"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@19:16"},"20:19":{"kind":"call","span":{"start":[20,19],"end":[20,43],"bytes":[647,671]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","method_name":"Builder","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":[],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@20:19"},"21:3":{"kind":"call","span":{"start":[21,3],"end":[21,36],"bytes":[675,708]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","method_name":"build","receiver_expr":"builder.add(\"a\").add(\"b\")","receiver_type":"StringUtil.Builder","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3"},"21:3/2":{"kind":"call","span":{"start":[21,3],"end":[21,28],"bytes":[675,700]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder.add(\"a\")","receiver_type":"StringUtil.Builder","argument_types":["\"b\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/2"},"21:3/3":{"kind":"call","span":{"start":[21,3],"end":[21,19],"bytes":[675,691]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder","receiver_type":"StringUtil.Builder","argument_types":["\"a\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/3"},"22:3":{"kind":"call","span":{"start":[22,3],"end":[22,20],"bytes":[712,729]},"callee":"can://slim/@external/(builtin)/log","method_name":"log","receiver_expr":"console","receiver_type":"Console","argument_types":["string"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@22:3"}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"6de6f6ff5a01a5c7c750a93d5e10bae7b15817f386421f45c7527cfb7259d9b3"},"src/models.ts":{"id":"can://slim/typescript/src/models.ts","kind":"module","span":{"start":[1,1],"end":[65,1],"bytes":[0,1237]},"source":"/** Domain models for the sample app. */\n\nexport interface Identifiable {\n readonly id: T;\n}\n\nexport interface Named {\n name: string;\n describe(): string;\n}\n\nexport type UserId = string | number;\n\nexport enum Role {\n Admin = \"admin\",\n Member = \"member\",\n Guest = \"guest\",\n}\n\nexport const enum Flag {\n None = 0,\n Active = 1,\n}\n\n/** A user of the system. */\nexport abstract class Entity implements Identifiable {\n constructor(public readonly id: ID) {}\n abstract describe(): string;\n}\n\nexport class User extends Entity implements Named {\n private loginCount = 0;\n static instances = 0;\n\n constructor(\n id: UserId,\n public name: string,\n private role: Role = Role.Member,\n ) {\n super(id);\n User.instances++;\n }\n\n get isAdmin(): boolean {\n return this.role === Role.Admin;\n }\n\n describe(): string {\n return `${this.name} (${this.role})`;\n }\n\n async recordLogin(): Promise {\n this.loginCount += 1;\n return this.loginCount;\n }\n}\n\n/** A second, unrelated implementer of Named — drives RTA subtype expansion. */\nexport class Robot implements Named {\n constructor(public name: string) {}\n describe(): string {\n return `robot:${this.name}`;\n }\n}\n","imports":[],"exports":[],"comments":[{"content":"/** Domain models for the sample app. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41},{"content":"/** A user of the system. */","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29},{"content":"/** A second, unrelated implementer of Named — drives RTA subtype expansion. */","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"types":{"Entity":{"id":"can://slim/typescript/src/models.ts/Entity","kind":"class","span":{"start":[26,1],"end":[29,2],"bytes":[376,521]},"name":"Entity","signature":"src/models.Entity","comments":[{"content":"A user of the system.","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29}],"decorators":[],"base_classes":["src/models.Identifiable"],"implements_types":["src/models.Identifiable"],"type_parameters":[{"name":"ID","default":"string"}],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Entity/describe","kind":"method","span":{"start":[28,3],"end":[28,31],"bytes":[491,519]},"name":"describe","signature":"src/models.Entity.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":true,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[{"parameters":[],"return_type":"string","type_parameters":[],"start_line":28,"end_line":28}],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Entity/constructor","kind":"constructor","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"name":"constructor","signature":"src/models.Entity.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"ID","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"public","decorators":[],"start_line":27,"end_line":27,"start_column":15,"end_column":37,"id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Entity/id","kind":"field","name":"id","type":"ID","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":true,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Identifiable"],"entrypoints":[],"is_entrypoint":false},"User":{"id":"can://slim/typescript/src/models.ts/User","kind":"class","span":{"start":[31,1],"end":[56,2],"bytes":[523,1015]},"name":"User","signature":"src/models.User","comments":[],"decorators":[],"base_classes":["src/models.Entity","src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/User/describe","kind":"method","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"name":"describe","signature":"src/models.User.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"recordLogin":{"id":"can://slim/typescript/src/models.ts/User/recordLogin","kind":"method","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"name":"recordLogin","signature":"src/models.User.recordLogin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/User/constructor","kind":"constructor","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"name":"constructor","signature":"src/models.User.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"UserId","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":36,"end_line":36,"start_column":5,"end_column":15,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0"},{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":37,"end_line":37,"start_column":5,"end_column":24,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"accessibility":"private","decorators":[],"start_line":38,"end_line":38,"start_column":5,"end_column":37,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"40:5":{"kind":"call","span":{"start":[40,5],"end":[40,14],"bytes":[738,747]},"callee":"can://slim/typescript/src/models.ts/Entity/constructor","method_name":"super","argument_types":["UserId"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/models.ts/User/constructor@40:5"}},"entrypoints":[],"is_entrypoint":false},"isAdmin#get":{"id":"can://slim/typescript/src/models.ts/User/isAdmin","kind":"getter","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"name":"isAdmin","signature":"src/models.User.isAdmin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"boolean","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"accessor_kind":"getter","overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"loginCount":{"id":"can://slim/typescript/src/models.ts/User/loginCount","kind":"field","span":{"start":[32,3],"end":[32,26],"bytes":[585,608]},"name":"loginCount","type":"number","comments":[],"decorators":[],"initializer":"0","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"instances":{"id":"can://slim/typescript/src/models.ts/User/instances","kind":"field","span":{"start":[33,3],"end":[33,24],"bytes":[611,632]},"name":"instances","type":"number","comments":[],"decorators":[],"initializer":"0","is_static":true,"is_readonly":false,"is_optional":false,"is_abstract":false},"name":{"id":"can://slim/typescript/src/models.ts/User/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"role":{"id":"can://slim/typescript/src/models.ts/User/role","kind":"field","name":"role","type":"Role","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":false,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"extends_ids":["can://slim/typescript/src/models.ts/Entity"],"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Robot":{"id":"can://slim/typescript/src/models.ts/Robot","kind":"class","span":{"start":[59,1],"end":[64,2],"bytes":[1099,1236]},"name":"Robot","signature":"src/models.Robot","comments":[{"content":"A second, unrelated implementer of Named — drives RTA subtype expansion.","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"decorators":[],"base_classes":["src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Robot/describe","kind":"method","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"name":"describe","signature":"src/models.Robot.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Robot/constructor","kind":"constructor","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"name":"constructor","signature":"src/models.Robot.constructor","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":60,"end_line":60,"start_column":15,"end_column":34,"id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Robot/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Identifiable":{"id":"can://slim/typescript/src/models.ts/Identifiable","kind":"interface","span":{"start":[3,1],"end":[5,2],"bytes":[42,105]},"name":"Identifiable","signature":"src/models.Identifiable","comments":[{"content":"Domain models for the sample app.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41}],"base_classes":[],"type_parameters":[{"name":"T","default":"string"}],"callables":{},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Identifiable/id","kind":"field","span":{"start":[4,3],"end":[4,18],"bytes":[88,103]},"name":"id","type":"T","comments":[],"decorators":[],"is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Named":{"id":"can://slim/typescript/src/models.ts/Named","kind":"interface","span":{"start":[7,1],"end":[10,2],"bytes":[107,171]},"name":"Named","signature":"src/models.Named","comments":[],"base_classes":[],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Named/describe","kind":"method","span":{"start":[9,3],"end":[9,22],"bytes":[150,169]},"name":"describe","signature":"src/models.Named.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Named/name","kind":"field","span":{"start":[8,3],"end":[8,16],"bytes":[134,147]},"name":"name","type":"string","comments":[],"decorators":[],"is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Role":{"id":"can://slim/typescript/src/models.ts/Role","kind":"enum","span":{"start":[14,1],"end":[18,2],"bytes":[212,291]},"name":"Role","signature":"src/models.Role","comments":[],"fields":{"Admin":{"id":"can://slim/typescript/src/models.ts/Role/Admin","kind":"field","span":{"start":[15,3],"end":[15,18],"bytes":[233,248]},"name":"Admin","value":"admin"},"Member":{"id":"can://slim/typescript/src/models.ts/Role/Member","kind":"field","span":{"start":[16,3],"end":[16,20],"bytes":[252,269]},"name":"Member","value":"member"},"Guest":{"id":"can://slim/typescript/src/models.ts/Role/Guest","kind":"field","span":{"start":[17,3],"end":[17,18],"bytes":[273,288]},"name":"Guest","value":"guest"}},"is_const":false,"is_exported":true,"is_ambient":false},"Flag":{"id":"can://slim/typescript/src/models.ts/Flag","kind":"enum","span":{"start":[20,1],"end":[23,2],"bytes":[293,345]},"name":"Flag","signature":"src/models.Flag","comments":[],"fields":{"None":{"id":"can://slim/typescript/src/models.ts/Flag/None","kind":"field","span":{"start":[21,3],"end":[21,11],"bytes":[320,328]},"name":"None","value":"0"},"Active":{"id":"can://slim/typescript/src/models.ts/Flag/Active","kind":"field","span":{"start":[22,3],"end":[22,13],"bytes":[332,342]},"name":"Active","value":"1"}},"is_const":true,"is_exported":true,"is_ambient":false},"UserId":{"id":"can://slim/typescript/src/models.ts/UserId","kind":"type_alias","span":{"start":[12,1],"end":[12,38],"bytes":[173,210]},"name":"UserId","signature":"src/models.UserId","comments":[],"aliased_type":"string | number","type_parameters":[],"is_exported":true,"is_ambient":false}},"functions":{},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d39ff571ccfda4b7c46923586b6b94d0e818a51be966f1ba40305650fd0ffc91"},"src/services.ts":{"id":"can://slim/typescript/src/services.ts","kind":"module","span":{"start":[1,1],"end":[48,1],"bytes":[0,1240]},"source":"import { type Named, Role, User, type UserId } from \"./models\";\n\n/** Pure helper — top-level function. */\nexport function makeGuestName(seed: number): string {\n return `guest-${seed}`;\n}\n\n/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */\nexport function announce(thing: Named): string {\n return thing.describe();\n}\n\n/** Arrow function bound to a const (function_expression-style callable). */\nexport const nextId = (n: number): UserId => n + 1;\n\nexport class UserService {\n private users: User[] = [];\n\n constructor(private readonly startId: number = 0) {}\n\n create(name: string, role: Role = Role.Member): User {\n const id = nextId(this.users.length + this.startId);\n const user = new User(id, name, role);\n this.users.push(user);\n return user;\n }\n\n createGuest(): User {\n const name = makeGuestName(this.users.length);\n return this.create(name, Role.Guest);\n }\n\n describeAll(): string[] {\n return this.users.map((u) => u.describe());\n }\n\n async loginAll(): Promise {\n let total = 0;\n for (const u of this.users) {\n total += await u.recordLogin();\n }\n return total;\n }\n}\n","imports":[{"module":"./models","name":"Named","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"UserId","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"}],"exports":[],"comments":[{"content":"/** Pure helper — top-level function. */","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41},{"content":"/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4},{"content":"/** Arrow function bound to a const (function_expression-style callable). */","is_docstring":true,"start_line":16,"end_line":16,"start_column":1,"end_column":77}],"types":{"UserService":{"id":"can://slim/typescript/src/services.ts/UserService","kind":"class","span":{"start":[19,1],"end":[47,2],"bytes":[558,1239]},"name":"UserService","signature":"src/services.UserService","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"create":{"id":"can://slim/typescript/src/services.ts/UserService/create","kind":"method","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"name":"create","signature":"src/services.UserService.create","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":10,"end_column":22,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":24,"end_column":48,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1"}],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"25:16":{"kind":"call","span":{"start":[25,16],"end":[25,56],"bytes":[744,784]},"callee":"can://slim/typescript/src/services.ts/nextId","method_name":"nextId","argument_types":["number"],"type_arguments":[],"return_type":"UserId","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@25:16"},"26:18":{"kind":"call","span":{"start":[26,18],"end":[26,42],"bytes":[803,827]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["UserId","string","Role"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@26:18"},"27:5":{"kind":"call","span":{"start":[27,5],"end":[27,26],"bytes":[833,854]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["User"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@27:5"}},"entrypoints":[],"is_entrypoint":false},"createGuest":{"id":"can://slim/typescript/src/services.ts/UserService/createGuest","kind":"method","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"name":"createGuest","signature":"src/services.UserService.createGuest","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"32:18":{"kind":"call","span":{"start":[32,18],"end":[32,50],"bytes":[919,951]},"callee":"can://slim/typescript/src/services.ts/makeGuestName","method_name":"makeGuestName","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:18"},"33:12":{"kind":"call","span":{"start":[33,12],"end":[33,41],"bytes":[964,993]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this","receiver_type":"this","argument_types":["string","Role.Guest"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:12"}},"entrypoints":[],"is_entrypoint":false},"describeAll":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll","kind":"method","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"name":"describeAll","signature":"src/services.UserService.describeAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:12":{"kind":"call","span":{"start":[37,12],"end":[37,47],"bytes":[1039,1074]},"callee":"can://slim/@external/(builtin)/map","method_name":"map","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["(u: User) => string"],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:12"}},"callables":{"":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"arrow","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"name":"(anonymous)","signature":"src/services.UserService.describeAll.","comments":[],"decorators":[],"parameters":[{"name":"u","type":"User","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":37,"end_line":37,"start_column":28,"end_column":29,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:34":{"kind":"call","span":{"start":[37,34],"end":[37,46],"bytes":[1061,1073]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34"}},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"loginAll":{"id":"can://slim/typescript/src/services.ts/UserService/loginAll","kind":"method","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"name":"loginAll","signature":"src/services.UserService.loginAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"43:22":{"kind":"call","span":{"start":[43,22],"end":[43,37],"bytes":[1193,1208]},"callee":"can://slim/typescript/src/models.ts/User/recordLogin","method_name":"recordLogin","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"Promise","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:22"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/services.ts/UserService/constructor","kind":"constructor","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"name":"constructor","signature":"src/services.UserService.constructor","comments":[],"decorators":[],"parameters":[{"name":"startId","type":"number","default_value":"0","is_optional":true,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":22,"end_line":22,"start_column":15,"end_column":51,"id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"users":{"id":"can://slim/typescript/src/services.ts/UserService/users","kind":"field","span":{"start":[20,3],"end":[20,30],"bytes":[587,614]},"name":"users","type":"User[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"startId":{"id":"can://slim/typescript/src/services.ts/UserService/startId","kind":"field","name":"startId","type":"number","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"makeGuestName":{"id":"can://slim/typescript/src/services.ts/makeGuestName","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"name":"makeGuestName","signature":"src/services.makeGuestName","comments":[{"content":"Pure helper — top-level function.","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41}],"decorators":[],"parameters":[{"name":"seed","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":31,"end_column":43,"id":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"announce":{"id":"can://slim/typescript/src/services.ts/announce","kind":"function","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"name":"announce","signature":"src/services.announce","comments":[{"content":"Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\nconcrete implementer of Named (User, Robot, ...).","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4}],"decorators":[],"parameters":[{"name":"thing","type":"Named","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":12,"end_line":12,"start_column":26,"end_column":38,"id":"can://slim/typescript/src/services.ts/announce@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"13:10":{"kind":"call","span":{"start":[13,10],"end":[13,26],"bytes":[407,423]},"callee":"can://slim/typescript/src/models.ts/Named/describe","method_name":"describe","receiver_expr":"thing","receiver_type":"Named","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/announce@13:10"}},"entrypoints":[],"is_entrypoint":false},"nextId":{"id":"can://slim/typescript/src/services.ts/nextId","kind":"arrow","span":{"start":[17,14],"end":[17,51],"bytes":[518,555]},"name":"nextId","signature":"src/services.nextId","comments":[],"decorators":[],"parameters":[{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":17,"end_line":17,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/services.ts/nextId@formal_in:0"}],"type_parameters":[],"return_type":"UserId","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"1bda3666dab48f8e686fb8ffc2143f2e422af62be46698053cfeea4184b55617"},"src/util.ts":{"id":"can://slim/typescript/src/util.ts","kind":"module","span":{"start":[1,1],"end":[35,1],"bytes":[0,949]},"source":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */\nexport namespace StringUtil {\n export function repeat(s: string, n: number): string {\n return slug(s).repeat(n);\n }\n\n export function slug(s: string): string {\n return s.toLowerCase().replace(/\\s+/g, \"-\");\n }\n\n export class Builder {\n private parts: string[] = [];\n add(part: string): this {\n this.parts.push(slug(part));\n return this;\n }\n build(): string {\n return this.parts.join(\"/\");\n }\n }\n}\n\n/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */\nexport function classify(items: T[]): Record {\n function keyOf(item: T): string {\n return item.name.charAt(0);\n }\n const out: Record = {};\n for (const item of items) {\n const k = keyOf(item);\n (out[k] ??= []).push(item);\n }\n return out;\n}\n","imports":[],"exports":[],"comments":[{"content":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106},{"content":"/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"types":{"StringUtil":{"id":"can://slim/typescript/src/util.ts/StringUtil","kind":"namespace","span":{"start":[2,1],"end":[21,2],"bytes":[106,543]},"name":"StringUtil","signature":"src/util.StringUtil","comments":[{"content":"A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106}],"types":{"Builder":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder","kind":"class","span":{"start":[11,3],"end":[20,4],"bytes":[328,541]},"name":"Builder","signature":"src/util.StringUtil.Builder","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"add":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","kind":"method","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"name":"add","signature":"src/util.StringUtil.Builder.add","comments":[],"decorators":[],"parameters":[{"name":"part","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":13,"end_line":13,"start_column":9,"end_column":21,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0"}],"type_parameters":[],"return_type":"this","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"14:7":{"kind":"call","span":{"start":[14,7],"end":[14,34],"bytes":[421,448]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["string"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7"},"14:23":{"kind":"call","span":{"start":[14,23],"end":[14,33],"bytes":[437,447]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:23"}},"entrypoints":[],"is_entrypoint":false},"build":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","kind":"method","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"name":"build","signature":"src/util.StringUtil.Builder.build","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"18:14":{"kind":"call","span":{"start":[18,14],"end":[18,34],"bytes":[510,530]},"callee":"can://slim/@external/(builtin)/join","method_name":"join","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["\"/\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:14"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","kind":"constructor","span":{"start":[0,0],"end":[0,0],"bytes":[0,0]},"name":"constructor","signature":"src/util.StringUtil.Builder.constructor","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":true,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"parts":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/parts","kind":"field","span":{"start":[12,5],"end":[12,34],"bytes":[355,384]},"name":"parts","type":"string[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"repeat":{"id":"can://slim/typescript/src/util.ts/StringUtil/repeat","kind":"function","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"name":"repeat","signature":"src/util.StringUtil.repeat","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":26,"end_column":35,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0"},{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":37,"end_column":46,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"4:12":{"kind":"call","span":{"start":[4,12],"end":[4,29],"bytes":[204,221]},"callee":"can://slim/@external/(builtin)/repeat","method_name":"repeat","receiver_expr":"slug(s)","receiver_type":"string","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12"},"4:12/2":{"kind":"call","span":{"start":[4,12],"end":[4,19],"bytes":[204,211]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12/2"}},"entrypoints":[],"is_entrypoint":false},"slug":{"id":"can://slim/typescript/src/util.ts/StringUtil/slug","kind":"function","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"name":"slug","signature":"src/util.StringUtil.slug","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"8:12":{"kind":"call","span":{"start":[8,12],"end":[8,48],"bytes":[283,319]},"callee":"can://slim/@external/(builtin)/replace","method_name":"replace","receiver_expr":"s.toLowerCase()","receiver_type":"string","argument_types":["RegExp","\"-\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12"},"8:12/2":{"kind":"call","span":{"start":[8,12],"end":[8,27],"bytes":[283,298]},"callee":"can://slim/@external/(builtin)/toLowerCase","method_name":"toLowerCase","receiver_expr":"s","receiver_type":"string","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12/2"}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_exported":true,"is_ambient":false}},"functions":{"classify":{"id":"can://slim/typescript/src/util.ts/classify","kind":"function","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"name":"classify","signature":"src/util.classify","comments":[{"content":"Generic top-level function with a nested helper, to exercise inner_callables + generics.","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"decorators":[],"parameters":[{"name":"items","type":"T[]","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":54,"end_column":64,"id":"can://slim/typescript/src/util.ts/classify@formal_in:0"}],"type_parameters":[{"name":"T","constraint":"{ name: string }"}],"return_type":"Record","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"30:15":{"kind":"call","span":{"start":[30,15],"end":[30,26],"bytes":[884,895]},"callee":"can://slim/typescript/src/util.ts/classify/keyOf","method_name":"keyOf","argument_types":["T"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@30:15"},"31:5":{"kind":"call","span":{"start":[31,5],"end":[31,31],"bytes":[901,927]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"(out[k] ??= [])","receiver_type":"T[]","argument_types":["T"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@31:5"}},"callables":{"keyOf":{"id":"can://slim/typescript/src/util.ts/classify/keyOf","kind":"function","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"name":"keyOf","signature":"src/util.classify.keyOf","comments":[],"decorators":[],"parameters":[{"name":"item","type":"T","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":25,"end_line":25,"start_column":18,"end_column":25,"id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,31],"bytes":[776,795]},"callee":"can://slim/@external/(builtin)/charAt","method_name":"charAt","receiver_expr":"item.name","receiver_type":"string","argument_types":["0"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:12"}},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"54886cff7e11ccadc987571f508b2aef2f324b14e63d8ad52100499851d130fa"}},"call_graph":[{"src":"can://slim/typescript/src/controllers.ts","dst":"can://slim/typescript/src/controllers.ts/Controller","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/index.ts","dst":"can://slim/typescript/src/index.ts/main","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Param","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/services.ts/UserService/describeAll","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/createGuest","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/list","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/show","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/announce","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/Robot/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/@external/(builtin)/log","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/models.ts/User/constructor","dst":"can://slim/typescript/src/models.ts/Entity/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Named/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Robot/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/services.ts/nextId","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/makeGuestName","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/@external/(builtin)/map","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll/","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/loginAll","dst":"can://slim/typescript/src/models.ts/User/recordLogin","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/typescript/src/util.ts/classify/keyOf","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify/keyOf","dst":"can://slim/@external/(builtin)/charAt","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/@external/(builtin)/repeat","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/replace","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/toLowerCase","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","dst":"can://slim/@external/(builtin)/join","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/typescript/src/services.ts/UserService/describeAll/","prov":["defuse"],"weight":1}],"param_in":[],"param_out":[],"artifacts":{"package.json":{"id":"can://slim/artifact/package.json","kind":"artifact","path":"package.json","format":"json","roles":["dependency-manifest","tool-config"],"size_bytes":88,"sha256":"277f174033b3f17dcd3ba9a550b53289624f034606303cef18a3f84ab7156c67","source":"{\n \"name\": \"sample-app\",\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"private\": true\n}\n","extraction":"none","config_keys":[]},"tsconfig.json":{"id":"can://slim/artifact/tsconfig.json","kind":"artifact","path":"tsconfig.json","format":"json","roles":["tool-config"],"size_bytes":289,"sha256":"72f24fc616456ab556dd8e7c886264214cb344547b32b972eb476467af0a9cab","source":"{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"experimentalDecorators\": true,\n \"emitDecoratorMetadata\": true\n },\n \"include\": [\"src/**/*.ts\"]\n}\n","extraction":"full","config_keys":[{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.target","key":"compilerOptions.target","namespace":"json","value":"ES2022","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.module","key":"compilerOptions.module","namespace":"json","value":"ESNext","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.moduleResolution","key":"compilerOptions.moduleResolution","namespace":"json","value":"bundler","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.strict","key":"compilerOptions.strict","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.esModuleInterop","key":"compilerOptions.esModuleInterop","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.skipLibCheck","key":"compilerOptions.skipLibCheck","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.experimentalDecorators","key":"compilerOptions.experimentalDecorators","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.emitDecoratorMetadata","key":"compilerOptions.emitDecoratorMetadata","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/include.0","key":"include.0","namespace":"json","value":"src/**/*.ts","references":[]}]}},"dependencies":[],"unresolved_imports":[],"config_uses":[],"config_reads":[],"entrypoint_report":{"frameworks_detected":[],"rulesets":["shipped"],"unresolved":{"Get":2,"Controller":1},"errors":[]},"external_symbols":{"can://slim/@external/(builtin)/log":{"id":"can://slim/@external/(builtin)/log","kind":"external","module":"(builtin)","name":"log"},"can://slim/@external/(builtin)/push":{"id":"can://slim/@external/(builtin)/push","kind":"external","module":"(builtin)","name":"push"},"can://slim/@external/(builtin)/map":{"id":"can://slim/@external/(builtin)/map","kind":"external","module":"(builtin)","name":"map"},"can://slim/@external/(builtin)/charAt":{"id":"can://slim/@external/(builtin)/charAt","kind":"external","module":"(builtin)","name":"charAt"},"can://slim/@external/(builtin)/repeat":{"id":"can://slim/@external/(builtin)/repeat","kind":"external","module":"(builtin)","name":"repeat"},"can://slim/@external/(builtin)/replace":{"id":"can://slim/@external/(builtin)/replace","kind":"external","module":"(builtin)","name":"replace"},"can://slim/@external/(builtin)/toLowerCase":{"id":"can://slim/@external/(builtin)/toLowerCase","kind":"external","module":"(builtin)","name":"toLowerCase"},"can://slim/@external/(builtin)/join":{"id":"can://slim/@external/(builtin)/join","kind":"external","module":"(builtin)","name":"join"}},"synthesized_callables":{"can://slim/typescript/src/controllers.ts/Controller@5:10":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Get@8:10":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Param@11:10":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"callable"},"can://slim/typescript/src/services.ts/UserService/describeAll@37:27":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"callable"}}}} \ No newline at end of file +{"schema_version":"2.0.0","language":"typescript","max_level":2,"analyzer":{"name":"codeanalyzer-typescript","version":"1.6.0"},"application":{"id":"can://slim","kind":"application","symbol_table":{"src/controllers.ts":{"id":"can://slim/typescript/src/controllers.ts","kind":"module","span":{"start":[1,1],"end":[29,1],"bytes":[0,699]},"source":"import { UserService } from \"./services\";\n\n// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.\nfunction Controller(prefix: string): ClassDecorator {\n return () => undefined;\n}\nfunction Get(path: string): MethodDecorator {\n return () => undefined;\n}\nfunction Param(name: string): ParameterDecorator {\n return () => undefined;\n}\n\n@Controller(\"/users\")\nexport class UserController {\n constructor(private readonly service: UserService) {}\n\n @Get(\"/:id\")\n show(@Param(\"id\") id: string): string {\n const user = this.service.create(id);\n return user.describe();\n }\n\n @Get(\"/\")\n list(): string[] {\n return this.service.describeAll();\n }\n}\n","imports":[{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":42,"resolved_module":"src/services.ts"}],"exports":[],"comments":[{"content":"// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.","is_docstring":false,"start_line":3,"end_line":3,"start_column":1,"end_column":101}],"types":{"UserController":{"id":"can://slim/typescript/src/controllers.ts/UserController","kind":"class","span":{"start":[14,1],"end":[28,2],"bytes":[380,698]},"name":"UserController","signature":"src/controllers.UserController","comments":[],"decorators":[{"name":"Controller","positional_arguments":["\"/users\""],"keyword_arguments":{},"start_line":14,"end_line":14,"start_column":1,"end_column":22}],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"show":{"id":"can://slim/typescript/src/controllers.ts/UserController/show","kind":"method","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"name":"show","signature":"src/controllers.UserController.show","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/:id\""],"keyword_arguments":{},"start_line":18,"end_line":18,"start_column":3,"end_column":15}],"parameters":[{"name":"id","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[{"name":"Param","positional_arguments":["\"id\""],"keyword_arguments":{},"start_line":19,"end_line":19,"start_column":8,"end_column":20}],"start_line":19,"end_line":19,"start_column":8,"end_column":31,"id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"20:18":{"kind":"call","span":{"start":[20,18],"end":[20,41],"bytes":[563,586]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this.service","receiver_type":"UserService","argument_types":["string"],"type_arguments":[],"return_type":"import(\"./models\").User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:18"},"21:12":{"kind":"call","span":{"start":[21,12],"end":[21,27],"bytes":[599,614]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"user","receiver_type":"import(\"./models\").User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:12"},"19:9":{"kind":"call","span":{"start":[19,9],"end":[19,20],"bytes":[512,523]},"callee":"can://slim/typescript/src/controllers.ts/Param","method_name":"Param","argument_types":["\"id\""],"type_arguments":[],"return_type":"ParameterDecorator","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@19:9"}},"entrypoints":[],"is_entrypoint":false},"list":{"id":"can://slim/typescript/src/controllers.ts/UserController/list","kind":"method","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"name":"list","signature":"src/controllers.UserController.list","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/\""],"keyword_arguments":{},"start_line":24,"end_line":24,"start_column":3,"end_column":12}],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,38],"bytes":[665,691]},"callee":"can://slim/typescript/src/services.ts/UserService/describeAll","method_name":"describeAll","receiver_expr":"this.service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:12"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/controllers.ts/UserController/constructor","kind":"constructor","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"name":"constructor","signature":"src/controllers.UserController.constructor","comments":[],"decorators":[],"parameters":[{"name":"service","type":"UserService","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":16,"end_line":16,"start_column":15,"end_column":52,"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"service":{"id":"can://slim/typescript/src/controllers.ts/UserController/service","kind":"field","name":"service","type":"UserService","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"Controller":{"id":"can://slim/typescript/src/controllers.ts/Controller","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"name":"Controller","signature":"src/controllers.Controller","comments":[],"decorators":[],"parameters":[{"name":"prefix","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":21,"end_column":35,"id":"can://slim/typescript/src/controllers.ts/Controller@formal_in:0"}],"type_parameters":[],"return_type":"ClassDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"arrow","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"name":"(anonymous)","signature":"src/controllers.Controller.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"Get":{"id":"can://slim/typescript/src/controllers.ts/Get","kind":"function","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"name":"Get","signature":"src/controllers.Get","comments":[],"decorators":[],"parameters":[{"name":"path","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":14,"end_column":26,"id":"can://slim/typescript/src/controllers.ts/Get@formal_in:0"}],"type_parameters":[],"return_type":"MethodDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"arrow","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"name":"(anonymous)","signature":"src/controllers.Get.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"Param":{"id":"can://slim/typescript/src/controllers.ts/Param","kind":"function","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"name":"Param","signature":"src/controllers.Param","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":10,"end_line":10,"start_column":16,"end_column":28,"id":"can://slim/typescript/src/controllers.ts/Param@formal_in:0"}],"type_parameters":[],"return_type":"ParameterDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"arrow","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"name":"(anonymous)","signature":"src/controllers.Param.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d42b8f615d51575e3436409b9fce70862182b6071da40471b4be9b95f7c9ee4c"},"src/index.ts":{"id":"can://slim/typescript/src/index.ts","kind":"module","span":{"start":[1,1],"end":[26,1],"bytes":[0,742]},"source":"import { UserController } from \"./controllers\";\nimport { Robot, Role, User } from \"./models\";\nimport { UserService, announce } from \"./services\";\nimport { StringUtil } from \"./util\";\n\nexport function main(): void {\n const service = new UserService(100);\n service.create(\"Ada\", Role.Admin);\n service.createGuest();\n\n const controller = new UserController(service);\n controller.list();\n controller.show(\"42\");\n\n // interface-typed dispatch — RTA should expand announce -> {User,Robot}.describe\n announce(new User(1, \"Ada\", Role.Admin));\n announce(new Robot(\"r2d2\"));\n\n const slug = StringUtil.repeat(\"hello world\", 2);\n const builder = new StringUtil.Builder();\n builder.add(\"a\").add(\"b\").build();\n console.log(slug);\n}\n\nmain();\n","imports":[{"module":"./controllers","name":"UserController","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":48,"resolved_module":"src/controllers.ts"},{"module":"./models","name":"Robot","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./services","name":"announce","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./util","name":"StringUtil","is_type_only":false,"import_kind":"named","start_line":4,"end_line":4,"start_column":1,"end_column":37,"resolved_module":"src/util.ts"}],"exports":[],"comments":[],"types":{},"functions":{"main":{"id":"can://slim/typescript/src/index.ts/main","kind":"function","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"name":"main","signature":"src/index.main","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"void","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"7:19":{"kind":"call","span":{"start":[7,19],"end":[7,39],"bytes":[233,253]},"callee":"can://slim/typescript/src/services.ts/UserService/constructor","method_name":"UserService","argument_types":["100"],"type_arguments":[],"return_type":"UserService","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@7:19"},"8:3":{"kind":"call","span":{"start":[8,3],"end":[8,36],"bytes":[257,290]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"service","receiver_type":"UserService","argument_types":["\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@8:3"},"9:3":{"kind":"call","span":{"start":[9,3],"end":[9,24],"bytes":[294,315]},"callee":"can://slim/typescript/src/services.ts/UserService/createGuest","method_name":"createGuest","receiver_expr":"service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@9:3"},"11:22":{"kind":"call","span":{"start":[11,22],"end":[11,49],"bytes":[339,366]},"callee":"can://slim/typescript/src/controllers.ts/UserController/constructor","method_name":"UserController","argument_types":["UserService"],"type_arguments":[],"return_type":"UserController","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@11:22"},"12:3":{"kind":"call","span":{"start":[12,3],"end":[12,20],"bytes":[370,387]},"callee":"can://slim/typescript/src/controllers.ts/UserController/list","method_name":"list","receiver_expr":"controller","receiver_type":"UserController","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@12:3"},"13:3":{"kind":"call","span":{"start":[13,3],"end":[13,24],"bytes":[391,412]},"callee":"can://slim/typescript/src/controllers.ts/UserController/show","method_name":"show","receiver_expr":"controller","receiver_type":"UserController","argument_types":["\"42\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@13:3"},"16:3":{"kind":"call","span":{"start":[16,3],"end":[16,43],"bytes":[503,543]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["User"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:3"},"16:12":{"kind":"call","span":{"start":[16,12],"end":[16,42],"bytes":[512,542]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["1","\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:12"},"17:3":{"kind":"call","span":{"start":[17,3],"end":[17,30],"bytes":[547,574]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["Robot"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:3"},"17:12":{"kind":"call","span":{"start":[17,12],"end":[17,29],"bytes":[556,573]},"callee":"can://slim/typescript/src/models.ts/Robot/constructor","method_name":"Robot","argument_types":["\"r2d2\""],"type_arguments":[],"return_type":"Robot","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:12"},"19:16":{"kind":"call","span":{"start":[19,16],"end":[19,51],"bytes":[592,627]},"callee":"can://slim/typescript/src/util.ts/StringUtil/repeat","method_name":"repeat","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":["\"hello world\"","2"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@19:16"},"20:19":{"kind":"call","span":{"start":[20,19],"end":[20,43],"bytes":[647,671]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","method_name":"Builder","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":[],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@20:19"},"21:3":{"kind":"call","span":{"start":[21,3],"end":[21,36],"bytes":[675,708]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","method_name":"build","receiver_expr":"builder.add(\"a\").add(\"b\")","receiver_type":"StringUtil.Builder","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3"},"21:3/2":{"kind":"call","span":{"start":[21,3],"end":[21,28],"bytes":[675,700]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder.add(\"a\")","receiver_type":"StringUtil.Builder","argument_types":["\"b\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/2"},"21:3/3":{"kind":"call","span":{"start":[21,3],"end":[21,19],"bytes":[675,691]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder","receiver_type":"StringUtil.Builder","argument_types":["\"a\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/3"},"22:3":{"kind":"call","span":{"start":[22,3],"end":[22,20],"bytes":[712,729]},"callee":"can://slim/@external/(builtin)/log","method_name":"log","receiver_expr":"console","receiver_type":"Console","argument_types":["string"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@22:3"}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"6de6f6ff5a01a5c7c750a93d5e10bae7b15817f386421f45c7527cfb7259d9b3"},"src/models.ts":{"id":"can://slim/typescript/src/models.ts","kind":"module","span":{"start":[1,1],"end":[65,1],"bytes":[0,1237]},"source":"/** Domain models for the sample app. */\n\nexport interface Identifiable {\n readonly id: T;\n}\n\nexport interface Named {\n name: string;\n describe(): string;\n}\n\nexport type UserId = string | number;\n\nexport enum Role {\n Admin = \"admin\",\n Member = \"member\",\n Guest = \"guest\",\n}\n\nexport const enum Flag {\n None = 0,\n Active = 1,\n}\n\n/** A user of the system. */\nexport abstract class Entity implements Identifiable {\n constructor(public readonly id: ID) {}\n abstract describe(): string;\n}\n\nexport class User extends Entity implements Named {\n private loginCount = 0;\n static instances = 0;\n\n constructor(\n id: UserId,\n public name: string,\n private role: Role = Role.Member,\n ) {\n super(id);\n User.instances++;\n }\n\n get isAdmin(): boolean {\n return this.role === Role.Admin;\n }\n\n describe(): string {\n return `${this.name} (${this.role})`;\n }\n\n async recordLogin(): Promise {\n this.loginCount += 1;\n return this.loginCount;\n }\n}\n\n/** A second, unrelated implementer of Named — drives RTA subtype expansion. */\nexport class Robot implements Named {\n constructor(public name: string) {}\n describe(): string {\n return `robot:${this.name}`;\n }\n}\n","imports":[],"exports":[],"comments":[{"content":"/** Domain models for the sample app. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41},{"content":"/** A user of the system. */","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29},{"content":"/** A second, unrelated implementer of Named — drives RTA subtype expansion. */","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"types":{"Entity":{"id":"can://slim/typescript/src/models.ts/Entity","kind":"class","span":{"start":[26,1],"end":[29,2],"bytes":[376,521]},"name":"Entity","signature":"src/models.Entity","comments":[{"content":"A user of the system.","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29}],"decorators":[],"base_classes":["src/models.Identifiable"],"implements_types":["src/models.Identifiable"],"type_parameters":[{"name":"ID","default":"string"}],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Entity/describe","kind":"method","span":{"start":[28,3],"end":[28,31],"bytes":[491,519]},"name":"describe","signature":"src/models.Entity.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":true,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[{"parameters":[],"return_type":"string","type_parameters":[],"start_line":28,"end_line":28}],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Entity/constructor","kind":"constructor","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"name":"constructor","signature":"src/models.Entity.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"ID","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"public","decorators":[],"start_line":27,"end_line":27,"start_column":15,"end_column":37,"id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Entity/id","kind":"field","name":"id","type":"ID","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":true,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Identifiable"],"entrypoints":[],"is_entrypoint":false},"User":{"id":"can://slim/typescript/src/models.ts/User","kind":"class","span":{"start":[31,1],"end":[56,2],"bytes":[523,1015]},"name":"User","signature":"src/models.User","comments":[],"decorators":[],"base_classes":["src/models.Entity","src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/User/describe","kind":"method","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"name":"describe","signature":"src/models.User.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"recordLogin":{"id":"can://slim/typescript/src/models.ts/User/recordLogin","kind":"method","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"name":"recordLogin","signature":"src/models.User.recordLogin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/User/constructor","kind":"constructor","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"name":"constructor","signature":"src/models.User.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"UserId","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":36,"end_line":36,"start_column":5,"end_column":15,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0"},{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":37,"end_line":37,"start_column":5,"end_column":24,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"accessibility":"private","decorators":[],"start_line":38,"end_line":38,"start_column":5,"end_column":37,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"40:5":{"kind":"call","span":{"start":[40,5],"end":[40,14],"bytes":[738,747]},"callee":"can://slim/typescript/src/models.ts/Entity/constructor","method_name":"super","argument_types":["UserId"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/models.ts/User/constructor@40:5"}},"entrypoints":[],"is_entrypoint":false},"isAdmin#get":{"id":"can://slim/typescript/src/models.ts/User/isAdmin","kind":"getter","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"name":"isAdmin","signature":"src/models.User.isAdmin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"boolean","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"accessor_kind":"getter","overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"loginCount":{"id":"can://slim/typescript/src/models.ts/User/loginCount","kind":"field","span":{"start":[32,3],"end":[32,26],"bytes":[585,608]},"name":"loginCount","type":"number","comments":[],"decorators":[],"initializer":"0","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"instances":{"id":"can://slim/typescript/src/models.ts/User/instances","kind":"field","span":{"start":[33,3],"end":[33,24],"bytes":[611,632]},"name":"instances","type":"number","comments":[],"decorators":[],"initializer":"0","is_static":true,"is_readonly":false,"is_optional":false,"is_abstract":false},"name":{"id":"can://slim/typescript/src/models.ts/User/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"role":{"id":"can://slim/typescript/src/models.ts/User/role","kind":"field","name":"role","type":"Role","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":false,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"extends_ids":["can://slim/typescript/src/models.ts/Entity"],"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Robot":{"id":"can://slim/typescript/src/models.ts/Robot","kind":"class","span":{"start":[59,1],"end":[64,2],"bytes":[1099,1236]},"name":"Robot","signature":"src/models.Robot","comments":[{"content":"A second, unrelated implementer of Named — drives RTA subtype expansion.","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"decorators":[],"base_classes":["src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Robot/describe","kind":"method","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"name":"describe","signature":"src/models.Robot.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Robot/constructor","kind":"constructor","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"name":"constructor","signature":"src/models.Robot.constructor","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":60,"end_line":60,"start_column":15,"end_column":34,"id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Robot/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Identifiable":{"id":"can://slim/typescript/src/models.ts/Identifiable","kind":"interface","span":{"start":[3,1],"end":[5,2],"bytes":[42,105]},"name":"Identifiable","signature":"src/models.Identifiable","comments":[{"content":"Domain models for the sample app.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41}],"base_classes":[],"type_parameters":[{"name":"T","default":"string"}],"callables":{},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Identifiable/id","kind":"field","span":{"start":[4,3],"end":[4,18],"bytes":[88,103]},"name":"id","type":"T","comments":[],"decorators":[],"is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Named":{"id":"can://slim/typescript/src/models.ts/Named","kind":"interface","span":{"start":[7,1],"end":[10,2],"bytes":[107,171]},"name":"Named","signature":"src/models.Named","comments":[],"base_classes":[],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Named/describe","kind":"method","span":{"start":[9,3],"end":[9,22],"bytes":[150,169]},"name":"describe","signature":"src/models.Named.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Named/name","kind":"field","span":{"start":[8,3],"end":[8,16],"bytes":[134,147]},"name":"name","type":"string","comments":[],"decorators":[],"is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Role":{"id":"can://slim/typescript/src/models.ts/Role","kind":"enum","span":{"start":[14,1],"end":[18,2],"bytes":[212,291]},"name":"Role","signature":"src/models.Role","comments":[],"fields":{"Admin":{"id":"can://slim/typescript/src/models.ts/Role/Admin","kind":"field","span":{"start":[15,3],"end":[15,18],"bytes":[233,248]},"name":"Admin","value":"admin"},"Member":{"id":"can://slim/typescript/src/models.ts/Role/Member","kind":"field","span":{"start":[16,3],"end":[16,20],"bytes":[252,269]},"name":"Member","value":"member"},"Guest":{"id":"can://slim/typescript/src/models.ts/Role/Guest","kind":"field","span":{"start":[17,3],"end":[17,18],"bytes":[273,288]},"name":"Guest","value":"guest"}},"is_const":false,"is_exported":true,"is_ambient":false},"Flag":{"id":"can://slim/typescript/src/models.ts/Flag","kind":"enum","span":{"start":[20,1],"end":[23,2],"bytes":[293,345]},"name":"Flag","signature":"src/models.Flag","comments":[],"fields":{"None":{"id":"can://slim/typescript/src/models.ts/Flag/None","kind":"field","span":{"start":[21,3],"end":[21,11],"bytes":[320,328]},"name":"None","value":"0"},"Active":{"id":"can://slim/typescript/src/models.ts/Flag/Active","kind":"field","span":{"start":[22,3],"end":[22,13],"bytes":[332,342]},"name":"Active","value":"1"}},"is_const":true,"is_exported":true,"is_ambient":false},"UserId":{"id":"can://slim/typescript/src/models.ts/UserId","kind":"type_alias","span":{"start":[12,1],"end":[12,38],"bytes":[173,210]},"name":"UserId","signature":"src/models.UserId","comments":[],"aliased_type":"string | number","type_parameters":[],"is_exported":true,"is_ambient":false}},"functions":{},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d39ff571ccfda4b7c46923586b6b94d0e818a51be966f1ba40305650fd0ffc91"},"src/services.ts":{"id":"can://slim/typescript/src/services.ts","kind":"module","span":{"start":[1,1],"end":[48,1],"bytes":[0,1240]},"source":"import { type Named, Role, User, type UserId } from \"./models\";\n\n/** Pure helper — top-level function. */\nexport function makeGuestName(seed: number): string {\n return `guest-${seed}`;\n}\n\n/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */\nexport function announce(thing: Named): string {\n return thing.describe();\n}\n\n/** Arrow function bound to a const (function_expression-style callable). */\nexport const nextId = (n: number): UserId => n + 1;\n\nexport class UserService {\n private users: User[] = [];\n\n constructor(private readonly startId: number = 0) {}\n\n create(name: string, role: Role = Role.Member): User {\n const id = nextId(this.users.length + this.startId);\n const user = new User(id, name, role);\n this.users.push(user);\n return user;\n }\n\n createGuest(): User {\n const name = makeGuestName(this.users.length);\n return this.create(name, Role.Guest);\n }\n\n describeAll(): string[] {\n return this.users.map((u) => u.describe());\n }\n\n async loginAll(): Promise {\n let total = 0;\n for (const u of this.users) {\n total += await u.recordLogin();\n }\n return total;\n }\n}\n","imports":[{"module":"./models","name":"Named","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"UserId","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"}],"exports":[],"comments":[{"content":"/** Pure helper — top-level function. */","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41},{"content":"/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4},{"content":"/** Arrow function bound to a const (function_expression-style callable). */","is_docstring":true,"start_line":16,"end_line":16,"start_column":1,"end_column":77}],"types":{"UserService":{"id":"can://slim/typescript/src/services.ts/UserService","kind":"class","span":{"start":[19,1],"end":[47,2],"bytes":[558,1239]},"name":"UserService","signature":"src/services.UserService","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"create":{"id":"can://slim/typescript/src/services.ts/UserService/create","kind":"method","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"name":"create","signature":"src/services.UserService.create","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":10,"end_column":22,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":24,"end_column":48,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1"}],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"25:16":{"kind":"call","span":{"start":[25,16],"end":[25,56],"bytes":[744,784]},"callee":"can://slim/typescript/src/services.ts/nextId","method_name":"nextId","argument_types":["number"],"type_arguments":[],"return_type":"UserId","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@25:16"},"26:18":{"kind":"call","span":{"start":[26,18],"end":[26,42],"bytes":[803,827]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["UserId","string","Role"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@26:18"},"27:5":{"kind":"call","span":{"start":[27,5],"end":[27,26],"bytes":[833,854]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["User"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@27:5"}},"entrypoints":[],"is_entrypoint":false},"createGuest":{"id":"can://slim/typescript/src/services.ts/UserService/createGuest","kind":"method","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"name":"createGuest","signature":"src/services.UserService.createGuest","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"32:18":{"kind":"call","span":{"start":[32,18],"end":[32,50],"bytes":[919,951]},"callee":"can://slim/typescript/src/services.ts/makeGuestName","method_name":"makeGuestName","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:18"},"33:12":{"kind":"call","span":{"start":[33,12],"end":[33,41],"bytes":[964,993]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this","receiver_type":"this","argument_types":["string","Role.Guest"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:12"}},"entrypoints":[],"is_entrypoint":false},"describeAll":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll","kind":"method","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"name":"describeAll","signature":"src/services.UserService.describeAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:12":{"kind":"call","span":{"start":[37,12],"end":[37,47],"bytes":[1039,1074]},"callee":"can://slim/@external/(builtin)/map","method_name":"map","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["(u: User) => string"],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:12"}},"callables":{"":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"arrow","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"name":"(anonymous)","signature":"src/services.UserService.describeAll.","comments":[],"decorators":[],"parameters":[{"name":"u","type":"User","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":37,"end_line":37,"start_column":28,"end_column":29,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:34":{"kind":"call","span":{"start":[37,34],"end":[37,46],"bytes":[1061,1073]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34"}},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false},"loginAll":{"id":"can://slim/typescript/src/services.ts/UserService/loginAll","kind":"method","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"name":"loginAll","signature":"src/services.UserService.loginAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"43:22":{"kind":"call","span":{"start":[43,22],"end":[43,37],"bytes":[1193,1208]},"callee":"can://slim/typescript/src/models.ts/User/recordLogin","method_name":"recordLogin","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"Promise","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:22"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/services.ts/UserService/constructor","kind":"constructor","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"name":"constructor","signature":"src/services.UserService.constructor","comments":[],"decorators":[],"parameters":[{"name":"startId","type":"number","default_value":"0","is_optional":true,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":22,"end_line":22,"start_column":15,"end_column":51,"id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"users":{"id":"can://slim/typescript/src/services.ts/UserService/users","kind":"field","span":{"start":[20,3],"end":[20,30],"bytes":[587,614]},"name":"users","type":"User[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"startId":{"id":"can://slim/typescript/src/services.ts/UserService/startId","kind":"field","name":"startId","type":"number","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"makeGuestName":{"id":"can://slim/typescript/src/services.ts/makeGuestName","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"name":"makeGuestName","signature":"src/services.makeGuestName","comments":[{"content":"Pure helper — top-level function.","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41}],"decorators":[],"parameters":[{"name":"seed","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":31,"end_column":43,"id":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false},"announce":{"id":"can://slim/typescript/src/services.ts/announce","kind":"function","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"name":"announce","signature":"src/services.announce","comments":[{"content":"Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\nconcrete implementer of Named (User, Robot, ...).","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4}],"decorators":[],"parameters":[{"name":"thing","type":"Named","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":12,"end_line":12,"start_column":26,"end_column":38,"id":"can://slim/typescript/src/services.ts/announce@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"13:10":{"kind":"call","span":{"start":[13,10],"end":[13,26],"bytes":[407,423]},"callee":"can://slim/typescript/src/models.ts/Named/describe","method_name":"describe","receiver_expr":"thing","receiver_type":"Named","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/announce@13:10"}},"entrypoints":[],"is_entrypoint":false},"nextId":{"id":"can://slim/typescript/src/services.ts/nextId","kind":"arrow","span":{"start":[17,14],"end":[17,51],"bytes":[518,555]},"name":"nextId","signature":"src/services.nextId","comments":[],"decorators":[],"parameters":[{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":17,"end_line":17,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/services.ts/nextId@formal_in:0"}],"type_parameters":[],"return_type":"UserId","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"1bda3666dab48f8e686fb8ffc2143f2e422af62be46698053cfeea4184b55617"},"src/util.ts":{"id":"can://slim/typescript/src/util.ts","kind":"module","span":{"start":[1,1],"end":[35,1],"bytes":[0,949]},"source":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */\nexport namespace StringUtil {\n export function repeat(s: string, n: number): string {\n return slug(s).repeat(n);\n }\n\n export function slug(s: string): string {\n return s.toLowerCase().replace(/\\s+/g, \"-\");\n }\n\n export class Builder {\n private parts: string[] = [];\n add(part: string): this {\n this.parts.push(slug(part));\n return this;\n }\n build(): string {\n return this.parts.join(\"/\");\n }\n }\n}\n\n/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */\nexport function classify(items: T[]): Record {\n function keyOf(item: T): string {\n return item.name.charAt(0);\n }\n const out: Record = {};\n for (const item of items) {\n const k = keyOf(item);\n (out[k] ??= []).push(item);\n }\n return out;\n}\n","imports":[],"exports":[],"comments":[{"content":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106},{"content":"/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"types":{"StringUtil":{"id":"can://slim/typescript/src/util.ts/StringUtil","kind":"namespace","span":{"start":[2,1],"end":[21,2],"bytes":[106,543]},"name":"StringUtil","signature":"src/util.StringUtil","comments":[{"content":"A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106}],"types":{"Builder":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder","kind":"class","span":{"start":[11,3],"end":[20,4],"bytes":[328,541]},"name":"Builder","signature":"src/util.StringUtil.Builder","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"add":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","kind":"method","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"name":"add","signature":"src/util.StringUtil.Builder.add","comments":[],"decorators":[],"parameters":[{"name":"part","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":13,"end_line":13,"start_column":9,"end_column":21,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0"}],"type_parameters":[],"return_type":"this","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"14:7":{"kind":"call","span":{"start":[14,7],"end":[14,34],"bytes":[421,448]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["string"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7"},"14:23":{"kind":"call","span":{"start":[14,23],"end":[14,33],"bytes":[437,447]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:23"}},"entrypoints":[],"is_entrypoint":false},"build":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","kind":"method","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"name":"build","signature":"src/util.StringUtil.Builder.build","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"18:14":{"kind":"call","span":{"start":[18,14],"end":[18,34],"bytes":[510,530]},"callee":"can://slim/@external/(builtin)/join","method_name":"join","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["\"/\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:14"}},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","kind":"constructor","span":{"start":[0,0],"end":[0,0],"bytes":[0,0]},"name":"constructor","signature":"src/util.StringUtil.Builder.constructor","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":true,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"parts":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/parts","kind":"field","span":{"start":[12,5],"end":[12,34],"bytes":[355,384]},"name":"parts","type":"string[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"repeat":{"id":"can://slim/typescript/src/util.ts/StringUtil/repeat","kind":"function","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"name":"repeat","signature":"src/util.StringUtil.repeat","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":26,"end_column":35,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0"},{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":37,"end_column":46,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"4:12":{"kind":"call","span":{"start":[4,12],"end":[4,29],"bytes":[204,221]},"callee":"can://slim/@external/(builtin)/repeat","method_name":"repeat","receiver_expr":"slug(s)","receiver_type":"string","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12"},"4:12/2":{"kind":"call","span":{"start":[4,12],"end":[4,19],"bytes":[204,211]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12/2"}},"entrypoints":[],"is_entrypoint":false},"slug":{"id":"can://slim/typescript/src/util.ts/StringUtil/slug","kind":"function","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"name":"slug","signature":"src/util.StringUtil.slug","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"8:12":{"kind":"call","span":{"start":[8,12],"end":[8,48],"bytes":[283,319]},"callee":"can://slim/@external/(builtin)/replace","method_name":"replace","receiver_expr":"s.toLowerCase()","receiver_type":"string","argument_types":["RegExp","\"-\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12"},"8:12/2":{"kind":"call","span":{"start":[8,12],"end":[8,27],"bytes":[283,298]},"callee":"can://slim/@external/(builtin)/toLowerCase","method_name":"toLowerCase","receiver_expr":"s","receiver_type":"string","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12/2"}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_exported":true,"is_ambient":false}},"functions":{"classify":{"id":"can://slim/typescript/src/util.ts/classify","kind":"function","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"name":"classify","signature":"src/util.classify","comments":[{"content":"Generic top-level function with a nested helper, to exercise inner_callables + generics.","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"decorators":[],"parameters":[{"name":"items","type":"T[]","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":54,"end_column":64,"id":"can://slim/typescript/src/util.ts/classify@formal_in:0"}],"type_parameters":[{"name":"T","constraint":"{ name: string }"}],"return_type":"Record","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"30:15":{"kind":"call","span":{"start":[30,15],"end":[30,26],"bytes":[884,895]},"callee":"can://slim/typescript/src/util.ts/classify/keyOf","method_name":"keyOf","argument_types":["T"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@30:15"},"31:5":{"kind":"call","span":{"start":[31,5],"end":[31,31],"bytes":[901,927]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"(out[k] ??= [])","receiver_type":"T[]","argument_types":["T"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@31:5"}},"callables":{"keyOf":{"id":"can://slim/typescript/src/util.ts/classify/keyOf","kind":"function","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"name":"keyOf","signature":"src/util.classify.keyOf","comments":[],"decorators":[],"parameters":[{"name":"item","type":"T","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":25,"end_line":25,"start_column":18,"end_column":25,"id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,31],"bytes":[776,795]},"callee":"can://slim/@external/(builtin)/charAt","method_name":"charAt","receiver_expr":"item.name","receiver_type":"string","argument_types":["0"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:12"}},"entrypoints":[],"is_entrypoint":false}},"entrypoints":[],"is_entrypoint":false}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"54886cff7e11ccadc987571f508b2aef2f324b14e63d8ad52100499851d130fa"}},"call_graph":[{"src":"can://slim/typescript/src/controllers.ts","dst":"can://slim/typescript/src/controllers.ts/Controller","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/index.ts","dst":"can://slim/typescript/src/index.ts/main","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Param","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/services.ts/UserService/describeAll","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/createGuest","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/list","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/show","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/announce","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/Robot/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/@external/(builtin)/log","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/models.ts/User/constructor","dst":"can://slim/typescript/src/models.ts/Entity/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Named/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Robot/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/services.ts/nextId","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/makeGuestName","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/@external/(builtin)/map","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll/","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/loginAll","dst":"can://slim/typescript/src/models.ts/User/recordLogin","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/typescript/src/util.ts/classify/keyOf","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify/keyOf","dst":"can://slim/@external/(builtin)/charAt","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/@external/(builtin)/repeat","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/replace","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/toLowerCase","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","dst":"can://slim/@external/(builtin)/join","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/typescript/src/services.ts/UserService/describeAll/","prov":["defuse"],"weight":1}],"param_in":[],"param_out":[],"artifacts":{"package.json":{"id":"can://slim/artifact/package.json","kind":"artifact","path":"package.json","format":"json","roles":["dependency-manifest","tool-config"],"size_bytes":88,"sha256":"277f174033b3f17dcd3ba9a550b53289624f034606303cef18a3f84ab7156c67","source":"{\n \"name\": \"sample-app\",\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"private\": true\n}\n","extraction":"none","config_keys":[]},"tsconfig.json":{"id":"can://slim/artifact/tsconfig.json","kind":"artifact","path":"tsconfig.json","format":"json","roles":["tool-config"],"size_bytes":289,"sha256":"72f24fc616456ab556dd8e7c886264214cb344547b32b972eb476467af0a9cab","source":"{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"experimentalDecorators\": true,\n \"emitDecoratorMetadata\": true\n },\n \"include\": [\"src/**/*.ts\"]\n}\n","extraction":"full","config_keys":[{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.target","key":"compilerOptions.target","namespace":"json","value":"ES2022","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.module","key":"compilerOptions.module","namespace":"json","value":"ESNext","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.moduleResolution","key":"compilerOptions.moduleResolution","namespace":"json","value":"bundler","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.strict","key":"compilerOptions.strict","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.esModuleInterop","key":"compilerOptions.esModuleInterop","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.skipLibCheck","key":"compilerOptions.skipLibCheck","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.experimentalDecorators","key":"compilerOptions.experimentalDecorators","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.emitDecoratorMetadata","key":"compilerOptions.emitDecoratorMetadata","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/include.0","key":"include.0","namespace":"json","value":"src/**/*.ts","references":[]}]}},"dependencies":[],"unresolved_imports":[],"config_uses":[],"config_reads":[],"entrypoint_report":{"frameworks_detected":[],"rulesets":["shipped"],"unresolved":{"Get":2,"Controller":1},"errors":[]},"external_symbols":{"can://slim/@external/(builtin)/log":{"id":"can://slim/@external/(builtin)/log","kind":"external","module":"(builtin)","name":"log"},"can://slim/@external/(builtin)/push":{"id":"can://slim/@external/(builtin)/push","kind":"external","module":"(builtin)","name":"push"},"can://slim/@external/(builtin)/map":{"id":"can://slim/@external/(builtin)/map","kind":"external","module":"(builtin)","name":"map"},"can://slim/@external/(builtin)/charAt":{"id":"can://slim/@external/(builtin)/charAt","kind":"external","module":"(builtin)","name":"charAt"},"can://slim/@external/(builtin)/repeat":{"id":"can://slim/@external/(builtin)/repeat","kind":"external","module":"(builtin)","name":"repeat"},"can://slim/@external/(builtin)/replace":{"id":"can://slim/@external/(builtin)/replace","kind":"external","module":"(builtin)","name":"replace"},"can://slim/@external/(builtin)/toLowerCase":{"id":"can://slim/@external/(builtin)/toLowerCase","kind":"external","module":"(builtin)","name":"toLowerCase"},"can://slim/@external/(builtin)/join":{"id":"can://slim/@external/(builtin)/join","kind":"external","module":"(builtin)","name":"join"}},"synthesized_callables":{"can://slim/typescript/src/controllers.ts/Controller@5:10":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Get@8:10":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Param@11:10":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"callable"},"can://slim/typescript/src/services.ts/UserService/describeAll@37:27":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"callable"}}}} \ No newline at end of file diff --git a/tests/resources/typescript/analysis_json/v2/a3/analysis.json b/tests/resources/typescript/analysis_json/v2/a3/analysis.json index 9de34c75..559dcced 100644 --- a/tests/resources/typescript/analysis_json/v2/a3/analysis.json +++ b/tests/resources/typescript/analysis_json/v2/a3/analysis.json @@ -1 +1 @@ -{"schema_version":"2.0.0","language":"typescript","max_level":3,"k_limit":3,"analyzer":{"name":"codeanalyzer-typescript","version":"1.5.3"},"application":{"id":"can://slim","kind":"application","symbol_table":{"src/controllers.ts":{"id":"can://slim/typescript/src/controllers.ts","kind":"module","span":{"start":[1,1],"end":[29,1],"bytes":[0,699]},"source":"import { UserService } from \"./services\";\n\n// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.\nfunction Controller(prefix: string): ClassDecorator {\n return () => undefined;\n}\nfunction Get(path: string): MethodDecorator {\n return () => undefined;\n}\nfunction Param(name: string): ParameterDecorator {\n return () => undefined;\n}\n\n@Controller(\"/users\")\nexport class UserController {\n constructor(private readonly service: UserService) {}\n\n @Get(\"/:id\")\n show(@Param(\"id\") id: string): string {\n const user = this.service.create(id);\n return user.describe();\n }\n\n @Get(\"/\")\n list(): string[] {\n return this.service.describeAll();\n }\n}\n","imports":[{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":42,"resolved_module":"src/services.ts"}],"exports":[],"comments":[{"content":"// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.","is_docstring":false,"start_line":3,"end_line":3,"start_column":1,"end_column":101}],"types":{"UserController":{"id":"can://slim/typescript/src/controllers.ts/UserController","kind":"class","span":{"start":[14,1],"end":[28,2],"bytes":[380,698]},"name":"UserController","signature":"src/controllers.UserController","comments":[],"decorators":[{"name":"Controller","positional_arguments":["\"/users\""],"keyword_arguments":{},"start_line":14,"end_line":14,"start_column":1,"end_column":22}],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"show":{"id":"can://slim/typescript/src/controllers.ts/UserController/show","kind":"method","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"name":"show","signature":"src/controllers.UserController.show","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/:id\""],"keyword_arguments":{},"start_line":18,"end_line":18,"start_column":3,"end_column":15}],"parameters":[{"name":"id","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[{"name":"Param","positional_arguments":["\"id\""],"keyword_arguments":{},"start_line":19,"end_line":19,"start_column":8,"end_column":20}],"start_line":19,"end_line":19,"start_column":8,"end_column":31,"id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"20:18":{"kind":"call","span":{"start":[20,18],"end":[20,41],"bytes":[563,586]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this.service","receiver_type":"UserService","argument_types":["string"],"type_arguments":[],"return_type":"import(\"./models\").User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:18"},"21:12":{"kind":"call","span":{"start":[21,12],"end":[21,27],"bytes":[599,614]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"user","receiver_type":"import(\"./models\").User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:12"},"19:9":{"kind":"call","span":{"start":[19,9],"end":[19,20],"bytes":[512,523]},"callee":"can://slim/typescript/src/controllers.ts/Param","method_name":"Param","argument_types":["\"id\""],"type_arguments":[],"return_type":"ParameterDecorator","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@19:9"},"@entry":{"kind":"entry","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@entry"},"20:5":{"kind":"statement","span":{"start":[20,5],"end":[20,42],"bytes":[550,587]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:5"},"21:5":{"kind":"statement","span":{"start":[21,5],"end":[21,28],"bytes":[592,615]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:5"},"@exit":{"kind":"exit","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"20:5","kind":"fallthrough"},{"src":"20:5","dst":"@exit","kind":"exception"},{"src":"20:5","dst":"21:5","kind":"fallthrough"},{"src":"21:5","dst":"@exit","kind":"exception"},{"src":"21:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"20:5"},{"src":"20:5","dst":"21:5"}],"ddg":[{"src":"@entry","dst":"20:5","var":"id","prov":["reaching-defs"]},{"src":"@entry","dst":"20:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"20:5","var":"this.service.create","prov":["reaching-defs"]},{"src":"20:5","dst":"21:5","var":"user.describe","prov":["reaching-defs"]}]},"list":{"id":"can://slim/typescript/src/controllers.ts/UserController/list","kind":"method","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"name":"list","signature":"src/controllers.UserController.list","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/\""],"keyword_arguments":{},"start_line":24,"end_line":24,"start_column":3,"end_column":12}],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,38],"bytes":[665,691]},"callee":"can://slim/typescript/src/services.ts/UserService/describeAll","method_name":"describeAll","receiver_expr":"this.service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:12"},"@entry":{"kind":"entry","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@entry"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,39],"bytes":[658,692]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:5"},"@exit":{"kind":"exit","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"26:5"}],"ddg":[{"src":"@entry","dst":"26:5","var":"this.service.describeAll","prov":["reaching-defs"]}]},"constructor":{"id":"can://slim/typescript/src/controllers.ts/UserController/constructor","kind":"constructor","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"name":"constructor","signature":"src/controllers.UserController.constructor","comments":[],"decorators":[],"parameters":[{"name":"service","type":"UserService","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":16,"end_line":16,"start_column":15,"end_column":52,"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[]}},"fields":{"service":{"id":"can://slim/typescript/src/controllers.ts/UserController/service","kind":"field","name":"service","type":"UserService","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"Controller":{"id":"can://slim/typescript/src/controllers.ts/Controller","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"name":"Controller","signature":"src/controllers.Controller","comments":[],"decorators":[],"parameters":[{"name":"prefix","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":21,"end_column":35,"id":"can://slim/typescript/src/controllers.ts/Controller@formal_in:0"}],"type_parameters":[],"return_type":"ClassDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"id":"can://slim/typescript/src/controllers.ts/Controller@entry"},"5:3":{"kind":"statement","span":{"start":[5,3],"end":[5,26],"bytes":[200,223]},"id":"can://slim/typescript/src/controllers.ts/Controller@5:3"},"@exit":{"kind":"exit","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"id":"can://slim/typescript/src/controllers.ts/Controller@exit"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"arrow","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"name":"(anonymous)","signature":"src/controllers.Controller.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@entry"},"5:16":{"kind":"statement","span":{"start":[5,16],"end":[5,25],"bytes":[213,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@5:16"},"@exit":{"kind":"exit","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:16","kind":"fallthrough"},{"src":"5:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:16"}],"ddg":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:3","kind":"fallthrough"},{"src":"5:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:3"}],"ddg":[]},"Get":{"id":"can://slim/typescript/src/controllers.ts/Get","kind":"function","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"name":"Get","signature":"src/controllers.Get","comments":[],"decorators":[],"parameters":[{"name":"path","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":14,"end_column":26,"id":"can://slim/typescript/src/controllers.ts/Get@formal_in:0"}],"type_parameters":[],"return_type":"MethodDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"id":"can://slim/typescript/src/controllers.ts/Get@entry"},"8:3":{"kind":"statement","span":{"start":[8,3],"end":[8,26],"bytes":[274,297]},"id":"can://slim/typescript/src/controllers.ts/Get@8:3"},"@exit":{"kind":"exit","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"id":"can://slim/typescript/src/controllers.ts/Get@exit"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"arrow","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"name":"(anonymous)","signature":"src/controllers.Get.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@entry"},"8:16":{"kind":"statement","span":{"start":[8,16],"end":[8,25],"bytes":[287,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@8:16"},"@exit":{"kind":"exit","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:16","kind":"fallthrough"},{"src":"8:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:16"}],"ddg":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:3","kind":"fallthrough"},{"src":"8:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:3"}],"ddg":[]},"Param":{"id":"can://slim/typescript/src/controllers.ts/Param","kind":"function","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"name":"Param","signature":"src/controllers.Param","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":10,"end_line":10,"start_column":16,"end_column":28,"id":"can://slim/typescript/src/controllers.ts/Param@formal_in:0"}],"type_parameters":[],"return_type":"ParameterDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"id":"can://slim/typescript/src/controllers.ts/Param@entry"},"11:3":{"kind":"statement","span":{"start":[11,3],"end":[11,26],"bytes":[353,376]},"id":"can://slim/typescript/src/controllers.ts/Param@11:3"},"@exit":{"kind":"exit","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"id":"can://slim/typescript/src/controllers.ts/Param@exit"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"arrow","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"name":"(anonymous)","signature":"src/controllers.Param.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@entry"},"11:16":{"kind":"statement","span":{"start":[11,16],"end":[11,25],"bytes":[366,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@11:16"},"@exit":{"kind":"exit","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"11:16","kind":"fallthrough"},{"src":"11:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"11:16"}],"ddg":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"11:3","kind":"fallthrough"},{"src":"11:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"11:3"}],"ddg":[]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d42b8f615d51575e3436409b9fce70862182b6071da40471b4be9b95f7c9ee4c"},"src/index.ts":{"id":"can://slim/typescript/src/index.ts","kind":"module","span":{"start":[1,1],"end":[26,1],"bytes":[0,742]},"source":"import { UserController } from \"./controllers\";\nimport { Robot, Role, User } from \"./models\";\nimport { UserService, announce } from \"./services\";\nimport { StringUtil } from \"./util\";\n\nexport function main(): void {\n const service = new UserService(100);\n service.create(\"Ada\", Role.Admin);\n service.createGuest();\n\n const controller = new UserController(service);\n controller.list();\n controller.show(\"42\");\n\n // interface-typed dispatch — RTA should expand announce -> {User,Robot}.describe\n announce(new User(1, \"Ada\", Role.Admin));\n announce(new Robot(\"r2d2\"));\n\n const slug = StringUtil.repeat(\"hello world\", 2);\n const builder = new StringUtil.Builder();\n builder.add(\"a\").add(\"b\").build();\n console.log(slug);\n}\n\nmain();\n","imports":[{"module":"./controllers","name":"UserController","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":48,"resolved_module":"src/controllers.ts"},{"module":"./models","name":"Robot","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./services","name":"announce","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./util","name":"StringUtil","is_type_only":false,"import_kind":"named","start_line":4,"end_line":4,"start_column":1,"end_column":37,"resolved_module":"src/util.ts"}],"exports":[],"comments":[],"types":{},"functions":{"main":{"id":"can://slim/typescript/src/index.ts/main","kind":"function","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"name":"main","signature":"src/index.main","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"void","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"7:19":{"kind":"call","span":{"start":[7,19],"end":[7,39],"bytes":[233,253]},"callee":"can://slim/typescript/src/services.ts/UserService/constructor","method_name":"UserService","argument_types":["100"],"type_arguments":[],"return_type":"UserService","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@7:19"},"8:3":{"kind":"call","span":{"start":[8,3],"end":[8,36],"bytes":[257,290]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"service","receiver_type":"UserService","argument_types":["\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@8:3"},"9:3":{"kind":"call","span":{"start":[9,3],"end":[9,24],"bytes":[294,315]},"callee":"can://slim/typescript/src/services.ts/UserService/createGuest","method_name":"createGuest","receiver_expr":"service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@9:3"},"11:22":{"kind":"call","span":{"start":[11,22],"end":[11,49],"bytes":[339,366]},"callee":"can://slim/typescript/src/controllers.ts/UserController/constructor","method_name":"UserController","argument_types":["UserService"],"type_arguments":[],"return_type":"UserController","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@11:22"},"12:3":{"kind":"call","span":{"start":[12,3],"end":[12,20],"bytes":[370,387]},"callee":"can://slim/typescript/src/controllers.ts/UserController/list","method_name":"list","receiver_expr":"controller","receiver_type":"UserController","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@12:3"},"13:3":{"kind":"call","span":{"start":[13,3],"end":[13,24],"bytes":[391,412]},"callee":"can://slim/typescript/src/controllers.ts/UserController/show","method_name":"show","receiver_expr":"controller","receiver_type":"UserController","argument_types":["\"42\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@13:3"},"16:3":{"kind":"call","span":{"start":[16,3],"end":[16,43],"bytes":[503,543]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["User"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:3"},"16:12":{"kind":"call","span":{"start":[16,12],"end":[16,42],"bytes":[512,542]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["1","\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:12"},"17:3":{"kind":"call","span":{"start":[17,3],"end":[17,30],"bytes":[547,574]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["Robot"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:3"},"17:12":{"kind":"call","span":{"start":[17,12],"end":[17,29],"bytes":[556,573]},"callee":"can://slim/typescript/src/models.ts/Robot/constructor","method_name":"Robot","argument_types":["\"r2d2\""],"type_arguments":[],"return_type":"Robot","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:12"},"19:16":{"kind":"call","span":{"start":[19,16],"end":[19,51],"bytes":[592,627]},"callee":"can://slim/typescript/src/util.ts/StringUtil/repeat","method_name":"repeat","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":["\"hello world\"","2"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@19:16"},"20:19":{"kind":"call","span":{"start":[20,19],"end":[20,43],"bytes":[647,671]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","method_name":"Builder","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":[],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@20:19"},"21:3":{"kind":"call","span":{"start":[21,3],"end":[21,36],"bytes":[675,708]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","method_name":"build","receiver_expr":"builder.add(\"a\").add(\"b\")","receiver_type":"StringUtil.Builder","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3"},"21:3/2":{"kind":"call","span":{"start":[21,3],"end":[21,28],"bytes":[675,700]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder.add(\"a\")","receiver_type":"StringUtil.Builder","argument_types":["\"b\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/2"},"21:3/3":{"kind":"call","span":{"start":[21,3],"end":[21,19],"bytes":[675,691]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder","receiver_type":"StringUtil.Builder","argument_types":["\"a\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/3"},"22:3":{"kind":"call","span":{"start":[22,3],"end":[22,20],"bytes":[712,729]},"callee":"can://slim/@external/(builtin)/log","method_name":"log","receiver_expr":"console","receiver_type":"Console","argument_types":["string"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@22:3"},"@entry":{"kind":"entry","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"id":"can://slim/typescript/src/index.ts/main@entry"},"7:3":{"kind":"statement","span":{"start":[7,3],"end":[7,40],"bytes":[217,254]},"id":"can://slim/typescript/src/index.ts/main@7:3"},"11:3":{"kind":"statement","span":{"start":[11,3],"end":[11,50],"bytes":[320,367]},"id":"can://slim/typescript/src/index.ts/main@11:3"},"19:3":{"kind":"statement","span":{"start":[19,3],"end":[19,52],"bytes":[579,628]},"id":"can://slim/typescript/src/index.ts/main@19:3"},"20:3":{"kind":"statement","span":{"start":[20,3],"end":[20,44],"bytes":[631,672]},"id":"can://slim/typescript/src/index.ts/main@20:3"},"@exit":{"kind":"exit","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"id":"can://slim/typescript/src/index.ts/main@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"7:3","kind":"fallthrough"},{"src":"11:3","dst":"@exit","kind":"exception"},{"src":"11:3","dst":"12:3","kind":"fallthrough"},{"src":"12:3","dst":"@exit","kind":"exception"},{"src":"12:3","dst":"13:3","kind":"fallthrough"},{"src":"13:3","dst":"@exit","kind":"exception"},{"src":"13:3","dst":"16:3","kind":"fallthrough"},{"src":"16:3","dst":"@exit","kind":"exception"},{"src":"16:3","dst":"17:3","kind":"fallthrough"},{"src":"17:3","dst":"@exit","kind":"exception"},{"src":"17:3","dst":"19:3","kind":"fallthrough"},{"src":"19:3","dst":"@exit","kind":"exception"},{"src":"19:3","dst":"20:3","kind":"fallthrough"},{"src":"20:3","dst":"@exit","kind":"exception"},{"src":"20:3","dst":"21:3","kind":"fallthrough"},{"src":"21:3","dst":"@exit","kind":"exception"},{"src":"21:3","dst":"22:3","kind":"fallthrough"},{"src":"22:3","dst":"@exit","kind":"exception"},{"src":"22:3","dst":"@exit","kind":"fallthrough"},{"src":"7:3","dst":"@exit","kind":"exception"},{"src":"7:3","dst":"8:3","kind":"fallthrough"},{"src":"8:3","dst":"@exit","kind":"exception"},{"src":"8:3","dst":"9:3","kind":"fallthrough"},{"src":"9:3","dst":"@exit","kind":"exception"},{"src":"9:3","dst":"11:3","kind":"fallthrough"}],"cdg":[{"src":"@entry","dst":"7:3"},{"src":"11:3","dst":"12:3"},{"src":"12:3","dst":"13:3"},{"src":"13:3","dst":"16:3"},{"src":"16:3","dst":"17:3"},{"src":"17:3","dst":"19:3"},{"src":"19:3","dst":"20:3"},{"src":"20:3","dst":"21:3"},{"src":"21:3","dst":"22:3"},{"src":"7:3","dst":"8:3"},{"src":"8:3","dst":"9:3"},{"src":"9:3","dst":"11:3"}],"ddg":[{"src":"@entry","dst":"13:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"8:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"9:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"11:3","dst":"12:3","var":"controller.list","prov":["reaching-defs"]},{"src":"11:3","dst":"13:3","var":"controller.show","prov":["reaching-defs"]},{"src":"19:3","dst":"22:3","var":"slug","prov":["reaching-defs"]},{"src":"20:3","dst":"21:3","var":"builder.add","prov":["reaching-defs"]},{"src":"7:3","dst":"11:3","var":"service","prov":["reaching-defs"]},{"src":"7:3","dst":"8:3","var":"service.create","prov":["reaching-defs"]},{"src":"7:3","dst":"9:3","var":"service.createGuest","prov":["reaching-defs"]}]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"6de6f6ff5a01a5c7c750a93d5e10bae7b15817f386421f45c7527cfb7259d9b3"},"src/models.ts":{"id":"can://slim/typescript/src/models.ts","kind":"module","span":{"start":[1,1],"end":[65,1],"bytes":[0,1237]},"source":"/** Domain models for the sample app. */\n\nexport interface Identifiable {\n readonly id: T;\n}\n\nexport interface Named {\n name: string;\n describe(): string;\n}\n\nexport type UserId = string | number;\n\nexport enum Role {\n Admin = \"admin\",\n Member = \"member\",\n Guest = \"guest\",\n}\n\nexport const enum Flag {\n None = 0,\n Active = 1,\n}\n\n/** A user of the system. */\nexport abstract class Entity implements Identifiable {\n constructor(public readonly id: ID) {}\n abstract describe(): string;\n}\n\nexport class User extends Entity implements Named {\n private loginCount = 0;\n static instances = 0;\n\n constructor(\n id: UserId,\n public name: string,\n private role: Role = Role.Member,\n ) {\n super(id);\n User.instances++;\n }\n\n get isAdmin(): boolean {\n return this.role === Role.Admin;\n }\n\n describe(): string {\n return `${this.name} (${this.role})`;\n }\n\n async recordLogin(): Promise {\n this.loginCount += 1;\n return this.loginCount;\n }\n}\n\n/** A second, unrelated implementer of Named — drives RTA subtype expansion. */\nexport class Robot implements Named {\n constructor(public name: string) {}\n describe(): string {\n return `robot:${this.name}`;\n }\n}\n","imports":[],"exports":[],"comments":[{"content":"/** Domain models for the sample app. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41},{"content":"/** A user of the system. */","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29},{"content":"/** A second, unrelated implementer of Named — drives RTA subtype expansion. */","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"types":{"Entity":{"id":"can://slim/typescript/src/models.ts/Entity","kind":"class","span":{"start":[26,1],"end":[29,2],"bytes":[376,521]},"name":"Entity","signature":"src/models.Entity","comments":[{"content":"A user of the system.","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29}],"decorators":[],"base_classes":["src/models.Identifiable"],"implements_types":["src/models.Identifiable"],"type_parameters":[{"name":"ID","default":"string"}],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Entity/describe","kind":"method","span":{"start":[28,3],"end":[28,31],"bytes":[491,519]},"name":"describe","signature":"src/models.Entity.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":true,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[{"parameters":[],"return_type":"string","type_parameters":[],"start_line":28,"end_line":28}],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Entity/constructor","kind":"constructor","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"name":"constructor","signature":"src/models.Entity.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"ID","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"public","decorators":[],"start_line":27,"end_line":27,"start_column":15,"end_column":37,"id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"id":"can://slim/typescript/src/models.ts/Entity/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"id":"can://slim/typescript/src/models.ts/Entity/constructor@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[]}},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Entity/id","kind":"field","name":"id","type":"ID","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":true,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Identifiable"],"entrypoints":[],"is_entrypoint":false},"User":{"id":"can://slim/typescript/src/models.ts/User","kind":"class","span":{"start":[31,1],"end":[56,2],"bytes":[523,1015]},"name":"User","signature":"src/models.User","comments":[],"decorators":[],"base_classes":["src/models.Entity","src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/User/describe","kind":"method","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"name":"describe","signature":"src/models.User.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"id":"can://slim/typescript/src/models.ts/User/describe@entry"},"49:5":{"kind":"statement","span":{"start":[49,5],"end":[49,42],"bytes":[872,909]},"id":"can://slim/typescript/src/models.ts/User/describe@49:5"},"@exit":{"kind":"exit","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"id":"can://slim/typescript/src/models.ts/User/describe@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"49:5","kind":"fallthrough"},{"src":"49:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"49:5"}],"ddg":[{"src":"@entry","dst":"49:5","var":"this.name","prov":["reaching-defs"]},{"src":"@entry","dst":"49:5","var":"this.role","prov":["reaching-defs"]}]},"recordLogin":{"id":"can://slim/typescript/src/models.ts/User/recordLogin","kind":"method","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"name":"recordLogin","signature":"src/models.User.recordLogin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@entry"},"53:5":{"kind":"statement","span":{"start":[53,5],"end":[53,26],"bytes":[960,981]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@53:5"},"54:5":{"kind":"statement","span":{"start":[54,5],"end":[54,28],"bytes":[986,1009]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@54:5"},"@exit":{"kind":"exit","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"53:5","kind":"fallthrough"},{"src":"53:5","dst":"54:5","kind":"fallthrough"},{"src":"54:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"53:5"},{"src":"@entry","dst":"54:5"}],"ddg":[{"src":"@entry","dst":"53:5","var":"this.loginCount","prov":["reaching-defs"]},{"src":"@entry","dst":"54:5","var":"this.loginCount","prov":["reaching-defs"]},{"src":"53:5","dst":"54:5","var":"this.loginCount","prov":["reaching-defs"]}]},"constructor":{"id":"can://slim/typescript/src/models.ts/User/constructor","kind":"constructor","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"name":"constructor","signature":"src/models.User.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"UserId","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":36,"end_line":36,"start_column":5,"end_column":15,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0"},{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":37,"end_line":37,"start_column":5,"end_column":24,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"accessibility":"private","decorators":[],"start_line":38,"end_line":38,"start_column":5,"end_column":37,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"40:5":{"kind":"call","span":{"start":[40,5],"end":[40,14],"bytes":[738,747]},"callee":"can://slim/typescript/src/models.ts/Entity/constructor","method_name":"super","argument_types":["UserId"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/models.ts/User/constructor@40:5"},"@entry":{"kind":"entry","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"id":"can://slim/typescript/src/models.ts/User/constructor@entry"},"41:5":{"kind":"statement","span":{"start":[41,5],"end":[41,22],"bytes":[753,770]},"id":"can://slim/typescript/src/models.ts/User/constructor@41:5"},"@exit":{"kind":"exit","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"id":"can://slim/typescript/src/models.ts/User/constructor@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"40:5","kind":"fallthrough"},{"src":"40:5","dst":"@exit","kind":"exception"},{"src":"40:5","dst":"41:5","kind":"fallthrough"},{"src":"41:5","dst":"@exit","kind":"fallthrough"}],"cdg":[{"src":"@entry","dst":"40:5"},{"src":"40:5","dst":"41:5"}],"ddg":[{"src":"@entry","dst":"40:5","var":"id","prov":["reaching-defs"]}]},"isAdmin#get":{"id":"can://slim/typescript/src/models.ts/User/isAdmin","kind":"getter","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"name":"isAdmin","signature":"src/models.User.isAdmin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"boolean","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"accessor_kind":"getter","overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@entry"},"45:5":{"kind":"statement","span":{"start":[45,5],"end":[45,37],"bytes":[807,839]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@45:5"},"@exit":{"kind":"exit","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"45:5","kind":"fallthrough"},{"src":"45:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"45:5"}],"ddg":[{"src":"@entry","dst":"45:5","var":"this.role","prov":["reaching-defs"]}]}},"fields":{"loginCount":{"id":"can://slim/typescript/src/models.ts/User/loginCount","kind":"field","span":{"start":[32,3],"end":[32,26],"bytes":[585,608]},"name":"loginCount","type":"number","comments":[],"decorators":[],"initializer":"0","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"instances":{"id":"can://slim/typescript/src/models.ts/User/instances","kind":"field","span":{"start":[33,3],"end":[33,24],"bytes":[611,632]},"name":"instances","type":"number","comments":[],"decorators":[],"initializer":"0","is_static":true,"is_readonly":false,"is_optional":false,"is_abstract":false},"name":{"id":"can://slim/typescript/src/models.ts/User/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"role":{"id":"can://slim/typescript/src/models.ts/User/role","kind":"field","name":"role","type":"Role","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":false,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"extends_ids":["can://slim/typescript/src/models.ts/Entity"],"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Robot":{"id":"can://slim/typescript/src/models.ts/Robot","kind":"class","span":{"start":[59,1],"end":[64,2],"bytes":[1099,1236]},"name":"Robot","signature":"src/models.Robot","comments":[{"content":"A second, unrelated implementer of Named — drives RTA subtype expansion.","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"decorators":[],"base_classes":["src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Robot/describe","kind":"method","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"name":"describe","signature":"src/models.Robot.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"id":"can://slim/typescript/src/models.ts/Robot/describe@entry"},"62:5":{"kind":"statement","span":{"start":[62,5],"end":[62,33],"bytes":[1202,1230]},"id":"can://slim/typescript/src/models.ts/Robot/describe@62:5"},"@exit":{"kind":"exit","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"id":"can://slim/typescript/src/models.ts/Robot/describe@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"62:5","kind":"fallthrough"},{"src":"62:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"62:5"}],"ddg":[{"src":"@entry","dst":"62:5","var":"this.name","prov":["reaching-defs"]}]},"constructor":{"id":"can://slim/typescript/src/models.ts/Robot/constructor","kind":"constructor","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"name":"constructor","signature":"src/models.Robot.constructor","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":60,"end_line":60,"start_column":15,"end_column":34,"id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"id":"can://slim/typescript/src/models.ts/Robot/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"id":"can://slim/typescript/src/models.ts/Robot/constructor@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[]}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Robot/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Identifiable":{"id":"can://slim/typescript/src/models.ts/Identifiable","kind":"interface","span":{"start":[3,1],"end":[5,2],"bytes":[42,105]},"name":"Identifiable","signature":"src/models.Identifiable","comments":[{"content":"Domain models for the sample app.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41}],"base_classes":[],"type_parameters":[{"name":"T","default":"string"}],"callables":{},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Identifiable/id","kind":"field","span":{"start":[4,3],"end":[4,18],"bytes":[88,103]},"name":"id","type":"T","comments":[],"decorators":[],"is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Named":{"id":"can://slim/typescript/src/models.ts/Named","kind":"interface","span":{"start":[7,1],"end":[10,2],"bytes":[107,171]},"name":"Named","signature":"src/models.Named","comments":[],"base_classes":[],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Named/describe","kind":"method","span":{"start":[9,3],"end":[9,22],"bytes":[150,169]},"name":"describe","signature":"src/models.Named.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Named/name","kind":"field","span":{"start":[8,3],"end":[8,16],"bytes":[134,147]},"name":"name","type":"string","comments":[],"decorators":[],"is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Role":{"id":"can://slim/typescript/src/models.ts/Role","kind":"enum","span":{"start":[14,1],"end":[18,2],"bytes":[212,291]},"name":"Role","signature":"src/models.Role","comments":[],"fields":{"Admin":{"id":"can://slim/typescript/src/models.ts/Role/Admin","kind":"field","span":{"start":[15,3],"end":[15,18],"bytes":[233,248]},"name":"Admin","value":"admin"},"Member":{"id":"can://slim/typescript/src/models.ts/Role/Member","kind":"field","span":{"start":[16,3],"end":[16,20],"bytes":[252,269]},"name":"Member","value":"member"},"Guest":{"id":"can://slim/typescript/src/models.ts/Role/Guest","kind":"field","span":{"start":[17,3],"end":[17,18],"bytes":[273,288]},"name":"Guest","value":"guest"}},"is_const":false,"is_exported":true,"is_ambient":false},"Flag":{"id":"can://slim/typescript/src/models.ts/Flag","kind":"enum","span":{"start":[20,1],"end":[23,2],"bytes":[293,345]},"name":"Flag","signature":"src/models.Flag","comments":[],"fields":{"None":{"id":"can://slim/typescript/src/models.ts/Flag/None","kind":"field","span":{"start":[21,3],"end":[21,11],"bytes":[320,328]},"name":"None","value":"0"},"Active":{"id":"can://slim/typescript/src/models.ts/Flag/Active","kind":"field","span":{"start":[22,3],"end":[22,13],"bytes":[332,342]},"name":"Active","value":"1"}},"is_const":true,"is_exported":true,"is_ambient":false},"UserId":{"id":"can://slim/typescript/src/models.ts/UserId","kind":"type_alias","span":{"start":[12,1],"end":[12,38],"bytes":[173,210]},"name":"UserId","signature":"src/models.UserId","comments":[],"aliased_type":"string | number","type_parameters":[],"is_exported":true,"is_ambient":false}},"functions":{},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d39ff571ccfda4b7c46923586b6b94d0e818a51be966f1ba40305650fd0ffc91"},"src/services.ts":{"id":"can://slim/typescript/src/services.ts","kind":"module","span":{"start":[1,1],"end":[48,1],"bytes":[0,1240]},"source":"import { type Named, Role, User, type UserId } from \"./models\";\n\n/** Pure helper — top-level function. */\nexport function makeGuestName(seed: number): string {\n return `guest-${seed}`;\n}\n\n/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */\nexport function announce(thing: Named): string {\n return thing.describe();\n}\n\n/** Arrow function bound to a const (function_expression-style callable). */\nexport const nextId = (n: number): UserId => n + 1;\n\nexport class UserService {\n private users: User[] = [];\n\n constructor(private readonly startId: number = 0) {}\n\n create(name: string, role: Role = Role.Member): User {\n const id = nextId(this.users.length + this.startId);\n const user = new User(id, name, role);\n this.users.push(user);\n return user;\n }\n\n createGuest(): User {\n const name = makeGuestName(this.users.length);\n return this.create(name, Role.Guest);\n }\n\n describeAll(): string[] {\n return this.users.map((u) => u.describe());\n }\n\n async loginAll(): Promise {\n let total = 0;\n for (const u of this.users) {\n total += await u.recordLogin();\n }\n return total;\n }\n}\n","imports":[{"module":"./models","name":"Named","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"UserId","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"}],"exports":[],"comments":[{"content":"/** Pure helper — top-level function. */","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41},{"content":"/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4},{"content":"/** Arrow function bound to a const (function_expression-style callable). */","is_docstring":true,"start_line":16,"end_line":16,"start_column":1,"end_column":77}],"types":{"UserService":{"id":"can://slim/typescript/src/services.ts/UserService","kind":"class","span":{"start":[19,1],"end":[47,2],"bytes":[558,1239]},"name":"UserService","signature":"src/services.UserService","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"create":{"id":"can://slim/typescript/src/services.ts/UserService/create","kind":"method","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"name":"create","signature":"src/services.UserService.create","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":10,"end_column":22,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":24,"end_column":48,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1"}],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"25:16":{"kind":"call","span":{"start":[25,16],"end":[25,56],"bytes":[744,784]},"callee":"can://slim/typescript/src/services.ts/nextId","method_name":"nextId","argument_types":["number"],"type_arguments":[],"return_type":"UserId","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@25:16"},"26:18":{"kind":"call","span":{"start":[26,18],"end":[26,42],"bytes":[803,827]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["UserId","string","Role"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@26:18"},"27:5":{"kind":"call","span":{"start":[27,5],"end":[27,26],"bytes":[833,854]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["User"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@27:5"},"@entry":{"kind":"entry","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"id":"can://slim/typescript/src/services.ts/UserService/create@entry"},"25:5":{"kind":"statement","span":{"start":[25,5],"end":[25,57],"bytes":[733,785]},"id":"can://slim/typescript/src/services.ts/UserService/create@25:5"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,43],"bytes":[790,828]},"id":"can://slim/typescript/src/services.ts/UserService/create@26:5"},"28:5":{"kind":"statement","span":{"start":[28,5],"end":[28,17],"bytes":[860,872]},"id":"can://slim/typescript/src/services.ts/UserService/create@28:5"},"@exit":{"kind":"exit","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"id":"can://slim/typescript/src/services.ts/UserService/create@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"25:5","kind":"fallthrough"},{"src":"25:5","dst":"@exit","kind":"exception"},{"src":"25:5","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"27:5","kind":"fallthrough"},{"src":"27:5","dst":"@exit","kind":"exception"},{"src":"27:5","dst":"28:5","kind":"fallthrough"},{"src":"28:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"25:5"},{"src":"25:5","dst":"26:5"},{"src":"26:5","dst":"27:5"},{"src":"27:5","dst":"28:5"}],"ddg":[{"src":"@entry","dst":"25:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5","var":"this.startId","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"26:5","var":"name","prov":["reaching-defs"]},{"src":"@entry","dst":"26:5","var":"role","prov":["reaching-defs"]},{"src":"@entry","dst":"27:5","var":"this.users.push","prov":["reaching-defs"]},{"src":"25:5","dst":"26:5","var":"id","prov":["reaching-defs"]},{"src":"26:5","dst":"27:5","var":"user","prov":["reaching-defs"]},{"src":"26:5","dst":"28:5","var":"user","prov":["reaching-defs"]}]},"createGuest":{"id":"can://slim/typescript/src/services.ts/UserService/createGuest","kind":"method","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"name":"createGuest","signature":"src/services.UserService.createGuest","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"32:18":{"kind":"call","span":{"start":[32,18],"end":[32,50],"bytes":[919,951]},"callee":"can://slim/typescript/src/services.ts/makeGuestName","method_name":"makeGuestName","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:18"},"33:12":{"kind":"call","span":{"start":[33,12],"end":[33,41],"bytes":[964,993]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this","receiver_type":"this","argument_types":["string","Role.Guest"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:12"},"@entry":{"kind":"entry","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@entry"},"32:5":{"kind":"statement","span":{"start":[32,5],"end":[32,51],"bytes":[906,952]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5"},"33:5":{"kind":"statement","span":{"start":[33,5],"end":[33,42],"bytes":[957,994]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5"},"@exit":{"kind":"exit","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"32:5","kind":"fallthrough"},{"src":"32:5","dst":"@exit","kind":"exception"},{"src":"32:5","dst":"33:5","kind":"fallthrough"},{"src":"33:5","dst":"@exit","kind":"exception"},{"src":"33:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"32:5"},{"src":"32:5","dst":"33:5"}],"ddg":[{"src":"@entry","dst":"32:5","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"33:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"33:5","var":"this.create","prov":["reaching-defs"]},{"src":"32:5","dst":"33:5","var":"name","prov":["reaching-defs"]}]},"describeAll":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll","kind":"method","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"name":"describeAll","signature":"src/services.UserService.describeAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:12":{"kind":"call","span":{"start":[37,12],"end":[37,47],"bytes":[1039,1074]},"callee":"can://slim/@external/(builtin)/map","method_name":"map","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["(u: User) => string"],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:12"},"@entry":{"kind":"entry","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@entry"},"37:5":{"kind":"statement","span":{"start":[37,5],"end":[37,48],"bytes":[1032,1075]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:5"},"@exit":{"kind":"exit","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@exit"}},"callables":{"":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"arrow","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"name":"(anonymous)","signature":"src/services.UserService.describeAll.","comments":[],"decorators":[],"parameters":[{"name":"u","type":"User","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":37,"end_line":37,"start_column":28,"end_column":29,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:34":{"kind":"call","span":{"start":[37,34],"end":[37,46],"bytes":[1061,1073]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34"},"@entry":{"kind":"entry","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@entry"},"@exit":{"kind":"exit","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"37:34","kind":"fallthrough"},{"src":"37:34","dst":"@exit","kind":"exception"},{"src":"37:34","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"37:34"}],"ddg":[{"src":"@entry","dst":"37:34","var":"u.describe","prov":["reaching-defs"]}]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"37:5","kind":"fallthrough"},{"src":"37:5","dst":"@exit","kind":"exception"},{"src":"37:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"37:5"}],"ddg":[{"src":"@entry","dst":"37:5","var":"this.users.map","prov":["reaching-defs"]}]},"loginAll":{"id":"can://slim/typescript/src/services.ts/UserService/loginAll","kind":"method","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"name":"loginAll","signature":"src/services.UserService.loginAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"43:22":{"kind":"call","span":{"start":[43,22],"end":[43,37],"bytes":[1193,1208]},"callee":"can://slim/typescript/src/models.ts/User/recordLogin","method_name":"recordLogin","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"Promise","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:22"},"@entry":{"kind":"entry","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@entry"},"41:5":{"kind":"statement","span":{"start":[41,5],"end":[41,19],"bytes":[1123,1137]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@41:5"},"42:5":{"kind":"statement","span":{"start":[42,5],"end":[44,6],"bytes":[1142,1215]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@42:5"},"43:7":{"kind":"statement","span":{"start":[43,7],"end":[43,38],"bytes":[1178,1209]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:7"},"45:5":{"kind":"statement","span":{"start":[45,5],"end":[45,18],"bytes":[1220,1233]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@45:5"},"@exit":{"kind":"exit","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"41:5","kind":"fallthrough"},{"src":"41:5","dst":"42:5","kind":"fallthrough"},{"src":"42:5","dst":"43:7","kind":"true"},{"src":"42:5","dst":"45:5","kind":"false"},{"src":"43:7","dst":"@exit","kind":"exception"},{"src":"43:7","dst":"42:5","kind":"loop_back"},{"src":"45:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"41:5"},{"src":"@entry","dst":"42:5"},{"src":"42:5","dst":"43:7"},{"src":"42:5","dst":"45:5"},{"src":"43:7","dst":"42:5"}],"ddg":[{"src":"@entry","dst":"42:5","var":"this.users","prov":["reaching-defs"]},{"src":"41:5","dst":"43:7","var":"total","prov":["reaching-defs"]},{"src":"41:5","dst":"45:5","var":"total","prov":["reaching-defs"]},{"src":"42:5","dst":"43:7","var":"u.recordLogin","prov":["reaching-defs"]},{"src":"43:7","dst":"43:7","var":"total","prov":["reaching-defs"]},{"src":"43:7","dst":"45:5","var":"total","prov":["reaching-defs"]}]},"constructor":{"id":"can://slim/typescript/src/services.ts/UserService/constructor","kind":"constructor","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"name":"constructor","signature":"src/services.UserService.constructor","comments":[],"decorators":[],"parameters":[{"name":"startId","type":"number","default_value":"0","is_optional":true,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":22,"end_line":22,"start_column":15,"end_column":51,"id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"id":"can://slim/typescript/src/services.ts/UserService/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"id":"can://slim/typescript/src/services.ts/UserService/constructor@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[]}},"fields":{"users":{"id":"can://slim/typescript/src/services.ts/UserService/users","kind":"field","span":{"start":[20,3],"end":[20,30],"bytes":[587,614]},"name":"users","type":"User[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"startId":{"id":"can://slim/typescript/src/services.ts/UserService/startId","kind":"field","name":"startId","type":"number","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"makeGuestName":{"id":"can://slim/typescript/src/services.ts/makeGuestName","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"name":"makeGuestName","signature":"src/services.makeGuestName","comments":[{"content":"Pure helper — top-level function.","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41}],"decorators":[],"parameters":[{"name":"seed","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":31,"end_column":43,"id":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"id":"can://slim/typescript/src/services.ts/makeGuestName@entry"},"5:3":{"kind":"statement","span":{"start":[5,3],"end":[5,26],"bytes":[164,187]},"id":"can://slim/typescript/src/services.ts/makeGuestName@5:3"},"@exit":{"kind":"exit","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"id":"can://slim/typescript/src/services.ts/makeGuestName@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:3","kind":"fallthrough"},{"src":"5:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:3"}],"ddg":[{"src":"@entry","dst":"5:3","var":"seed","prov":["reaching-defs"]}]},"announce":{"id":"can://slim/typescript/src/services.ts/announce","kind":"function","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"name":"announce","signature":"src/services.announce","comments":[{"content":"Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\nconcrete implementer of Named (User, Robot, ...).","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4}],"decorators":[],"parameters":[{"name":"thing","type":"Named","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":12,"end_line":12,"start_column":26,"end_column":38,"id":"can://slim/typescript/src/services.ts/announce@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"13:10":{"kind":"call","span":{"start":[13,10],"end":[13,26],"bytes":[407,423]},"callee":"can://slim/typescript/src/models.ts/Named/describe","method_name":"describe","receiver_expr":"thing","receiver_type":"Named","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/announce@13:10"},"@entry":{"kind":"entry","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"id":"can://slim/typescript/src/services.ts/announce@entry"},"13:3":{"kind":"statement","span":{"start":[13,3],"end":[13,27],"bytes":[400,424]},"id":"can://slim/typescript/src/services.ts/announce@13:3"},"@exit":{"kind":"exit","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"id":"can://slim/typescript/src/services.ts/announce@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"13:3","kind":"fallthrough"},{"src":"13:3","dst":"@exit","kind":"exception"},{"src":"13:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"13:3"}],"ddg":[{"src":"@entry","dst":"13:3","var":"thing.describe","prov":["reaching-defs"]}]},"nextId":{"id":"can://slim/typescript/src/services.ts/nextId","kind":"arrow","span":{"start":[17,14],"end":[17,51],"bytes":[518,555]},"name":"nextId","signature":"src/services.nextId","comments":[],"decorators":[],"parameters":[{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":17,"end_line":17,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/services.ts/nextId@formal_in:0"}],"type_parameters":[],"return_type":"UserId","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[17,23],"end":[17,51],"bytes":[527,555]},"id":"can://slim/typescript/src/services.ts/nextId@entry"},"17:46":{"kind":"statement","span":{"start":[17,46],"end":[17,51],"bytes":[550,555]},"id":"can://slim/typescript/src/services.ts/nextId@17:46"},"@exit":{"kind":"exit","span":{"start":[17,23],"end":[17,51],"bytes":[527,555]},"id":"can://slim/typescript/src/services.ts/nextId@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"17:46","kind":"fallthrough"},{"src":"17:46","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"17:46"}],"ddg":[{"src":"@entry","dst":"17:46","var":"n","prov":["reaching-defs"]}]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"1bda3666dab48f8e686fb8ffc2143f2e422af62be46698053cfeea4184b55617"},"src/util.ts":{"id":"can://slim/typescript/src/util.ts","kind":"module","span":{"start":[1,1],"end":[35,1],"bytes":[0,949]},"source":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */\nexport namespace StringUtil {\n export function repeat(s: string, n: number): string {\n return slug(s).repeat(n);\n }\n\n export function slug(s: string): string {\n return s.toLowerCase().replace(/\\s+/g, \"-\");\n }\n\n export class Builder {\n private parts: string[] = [];\n add(part: string): this {\n this.parts.push(slug(part));\n return this;\n }\n build(): string {\n return this.parts.join(\"/\");\n }\n }\n}\n\n/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */\nexport function classify(items: T[]): Record {\n function keyOf(item: T): string {\n return item.name.charAt(0);\n }\n const out: Record = {};\n for (const item of items) {\n const k = keyOf(item);\n (out[k] ??= []).push(item);\n }\n return out;\n}\n","imports":[],"exports":[],"comments":[{"content":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106},{"content":"/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"types":{"StringUtil":{"id":"can://slim/typescript/src/util.ts/StringUtil","kind":"namespace","span":{"start":[2,1],"end":[21,2],"bytes":[106,543]},"name":"StringUtil","signature":"src/util.StringUtil","comments":[{"content":"A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106}],"types":{"Builder":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder","kind":"class","span":{"start":[11,3],"end":[20,4],"bytes":[328,541]},"name":"Builder","signature":"src/util.StringUtil.Builder","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"add":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","kind":"method","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"name":"add","signature":"src/util.StringUtil.Builder.add","comments":[],"decorators":[],"parameters":[{"name":"part","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":13,"end_line":13,"start_column":9,"end_column":21,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0"}],"type_parameters":[],"return_type":"this","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"14:7":{"kind":"call","span":{"start":[14,7],"end":[14,34],"bytes":[421,448]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["string"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7"},"14:23":{"kind":"call","span":{"start":[14,23],"end":[14,33],"bytes":[437,447]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:23"},"@entry":{"kind":"entry","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@entry"},"15:7":{"kind":"statement","span":{"start":[15,7],"end":[15,19],"bytes":[456,468]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@15:7"},"@exit":{"kind":"exit","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"14:7","kind":"fallthrough"},{"src":"14:7","dst":"@exit","kind":"exception"},{"src":"14:7","dst":"15:7","kind":"fallthrough"},{"src":"15:7","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"14:7"},{"src":"14:7","dst":"15:7"}],"ddg":[{"src":"@entry","dst":"14:7","var":"part","prov":["reaching-defs"]},{"src":"@entry","dst":"14:7","var":"this.parts.push","prov":["reaching-defs"]},{"src":"@entry","dst":"15:7","var":"this","prov":["reaching-defs"]}]},"build":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","kind":"method","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"name":"build","signature":"src/util.StringUtil.Builder.build","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"18:14":{"kind":"call","span":{"start":[18,14],"end":[18,34],"bytes":[510,530]},"callee":"can://slim/@external/(builtin)/join","method_name":"join","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["\"/\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:14"},"@entry":{"kind":"entry","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@entry"},"18:7":{"kind":"statement","span":{"start":[18,7],"end":[18,35],"bytes":[503,531]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:7"},"@exit":{"kind":"exit","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"18:7","kind":"fallthrough"},{"src":"18:7","dst":"@exit","kind":"exception"},{"src":"18:7","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"18:7"}],"ddg":[{"src":"@entry","dst":"18:7","var":"this.parts.join","prov":["reaching-defs"]}]},"constructor":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","kind":"constructor","span":{"start":[0,0],"end":[0,0],"bytes":[0,0]},"name":"constructor","signature":"src/util.StringUtil.Builder.constructor","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":true,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"parts":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/parts","kind":"field","span":{"start":[12,5],"end":[12,34],"bytes":[355,384]},"name":"parts","type":"string[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"repeat":{"id":"can://slim/typescript/src/util.ts/StringUtil/repeat","kind":"function","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"name":"repeat","signature":"src/util.StringUtil.repeat","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":26,"end_column":35,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0"},{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":37,"end_column":46,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"4:12":{"kind":"call","span":{"start":[4,12],"end":[4,29],"bytes":[204,221]},"callee":"can://slim/@external/(builtin)/repeat","method_name":"repeat","receiver_expr":"slug(s)","receiver_type":"string","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12"},"4:12/2":{"kind":"call","span":{"start":[4,12],"end":[4,19],"bytes":[204,211]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12/2"},"@entry":{"kind":"entry","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@entry"},"4:5":{"kind":"statement","span":{"start":[4,5],"end":[4,30],"bytes":[197,222]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5"},"@exit":{"kind":"exit","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"4:5","kind":"fallthrough"},{"src":"4:5","dst":"@exit","kind":"exception"},{"src":"4:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"4:5"}],"ddg":[{"src":"@entry","dst":"4:5","var":"n","prov":["reaching-defs"]},{"src":"@entry","dst":"4:5","var":"s","prov":["reaching-defs"]}]},"slug":{"id":"can://slim/typescript/src/util.ts/StringUtil/slug","kind":"function","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"name":"slug","signature":"src/util.StringUtil.slug","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"8:12":{"kind":"call","span":{"start":[8,12],"end":[8,48],"bytes":[283,319]},"callee":"can://slim/@external/(builtin)/replace","method_name":"replace","receiver_expr":"s.toLowerCase()","receiver_type":"string","argument_types":["RegExp","\"-\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12"},"8:12/2":{"kind":"call","span":{"start":[8,12],"end":[8,27],"bytes":[283,298]},"callee":"can://slim/@external/(builtin)/toLowerCase","method_name":"toLowerCase","receiver_expr":"s","receiver_type":"string","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12/2"},"@entry":{"kind":"entry","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@entry"},"8:5":{"kind":"statement","span":{"start":[8,5],"end":[8,49],"bytes":[276,320]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:5"},"@exit":{"kind":"exit","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:5","kind":"fallthrough"},{"src":"8:5","dst":"@exit","kind":"exception"},{"src":"8:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:5"}],"ddg":[{"src":"@entry","dst":"8:5","var":"s.toLowerCase","prov":["reaching-defs"]}]}},"fields":{},"is_exported":true,"is_ambient":false}},"functions":{"classify":{"id":"can://slim/typescript/src/util.ts/classify","kind":"function","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"name":"classify","signature":"src/util.classify","comments":[{"content":"Generic top-level function with a nested helper, to exercise inner_callables + generics.","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"decorators":[],"parameters":[{"name":"items","type":"T[]","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":54,"end_column":64,"id":"can://slim/typescript/src/util.ts/classify@formal_in:0"}],"type_parameters":[{"name":"T","constraint":"{ name: string }"}],"return_type":"Record","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"30:15":{"kind":"call","span":{"start":[30,15],"end":[30,26],"bytes":[884,895]},"callee":"can://slim/typescript/src/util.ts/classify/keyOf","method_name":"keyOf","argument_types":["T"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@30:15"},"31:5":{"kind":"call","span":{"start":[31,5],"end":[31,31],"bytes":[901,927]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"(out[k] ??= [])","receiver_type":"T[]","argument_types":["T"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@31:5"},"@entry":{"kind":"entry","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"id":"can://slim/typescript/src/util.ts/classify@entry"},"25:3":{"kind":"statement","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify@25:3"},"28:3":{"kind":"statement","span":{"start":[28,3],"end":[28,39],"bytes":[803,839]},"id":"can://slim/typescript/src/util.ts/classify@28:3"},"29:3":{"kind":"statement","span":{"start":[29,3],"end":[32,4],"bytes":[842,932]},"id":"can://slim/typescript/src/util.ts/classify@29:3"},"30:5":{"kind":"statement","span":{"start":[30,5],"end":[30,27],"bytes":[874,896]},"id":"can://slim/typescript/src/util.ts/classify@30:5"},"33:3":{"kind":"statement","span":{"start":[33,3],"end":[33,14],"bytes":[935,946]},"id":"can://slim/typescript/src/util.ts/classify@33:3"},"@exit":{"kind":"exit","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"id":"can://slim/typescript/src/util.ts/classify@exit"}},"callables":{"keyOf":{"id":"can://slim/typescript/src/util.ts/classify/keyOf","kind":"function","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"name":"keyOf","signature":"src/util.classify.keyOf","comments":[],"decorators":[],"parameters":[{"name":"item","type":"T","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":25,"end_line":25,"start_column":18,"end_column":25,"id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,31],"bytes":[776,795]},"callee":"can://slim/@external/(builtin)/charAt","method_name":"charAt","receiver_expr":"item.name","receiver_type":"string","argument_types":["0"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:12"},"@entry":{"kind":"entry","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@entry"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,32],"bytes":[769,796]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:5"},"@exit":{"kind":"exit","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"26:5"}],"ddg":[{"src":"@entry","dst":"26:5","var":"item.name.charAt","prov":["reaching-defs"]}]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"25:3","kind":"fallthrough"},{"src":"25:3","dst":"@exit","kind":"exception"},{"src":"25:3","dst":"28:3","kind":"fallthrough"},{"src":"28:3","dst":"29:3","kind":"fallthrough"},{"src":"29:3","dst":"30:5","kind":"true"},{"src":"29:3","dst":"33:3","kind":"false"},{"src":"30:5","dst":"@exit","kind":"exception"},{"src":"30:5","dst":"31:5","kind":"fallthrough"},{"src":"31:5","dst":"@exit","kind":"exception"},{"src":"31:5","dst":"29:3","kind":"loop_back"},{"src":"33:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"25:3"},{"src":"25:3","dst":"28:3"},{"src":"25:3","dst":"29:3"},{"src":"29:3","dst":"30:5"},{"src":"29:3","dst":"33:3"},{"src":"30:5","dst":"31:5"},{"src":"31:5","dst":"29:3"}],"ddg":[{"src":"@entry","dst":"29:3","var":"items","prov":["reaching-defs"]},{"src":"28:3","dst":"31:5","var":"out[*]","prov":["reaching-defs"]},{"src":"28:3","dst":"33:3","var":"out","prov":["reaching-defs"]},{"src":"29:3","dst":"30:5","var":"item","prov":["reaching-defs"]},{"src":"29:3","dst":"31:5","var":"item","prov":["reaching-defs"]},{"src":"30:5","dst":"31:5","var":"k","prov":["reaching-defs"]},{"src":"31:5","dst":"31:5","var":"out[*]","prov":["reaching-defs"]},{"src":"31:5","dst":"33:3","var":"out","prov":["reaching-defs"]}]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"54886cff7e11ccadc987571f508b2aef2f324b14e63d8ad52100499851d130fa"}},"call_graph":[{"src":"can://slim/typescript/src/controllers.ts","dst":"can://slim/typescript/src/controllers.ts/Controller","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/index.ts","dst":"can://slim/typescript/src/index.ts/main","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Param","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/services.ts/UserService/describeAll","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/createGuest","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/list","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/show","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/announce","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/Robot/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/@external/(builtin)/log","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/models.ts/User/constructor","dst":"can://slim/typescript/src/models.ts/Entity/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Named/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Robot/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/services.ts/nextId","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/makeGuestName","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/@external/(builtin)/map","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll/","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/loginAll","dst":"can://slim/typescript/src/models.ts/User/recordLogin","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/typescript/src/util.ts/classify/keyOf","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify/keyOf","dst":"can://slim/@external/(builtin)/charAt","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/@external/(builtin)/repeat","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/replace","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/toLowerCase","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","dst":"can://slim/@external/(builtin)/join","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/typescript/src/services.ts/UserService/describeAll/","prov":["defuse"],"weight":1}],"param_in":[],"param_out":[],"artifacts":{"package.json":{"id":"can://slim/artifact/package.json","kind":"artifact","path":"package.json","format":"json","roles":["dependency-manifest","tool-config"],"size_bytes":88,"sha256":"277f174033b3f17dcd3ba9a550b53289624f034606303cef18a3f84ab7156c67","source":"{\n \"name\": \"sample-app\",\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"private\": true\n}\n","extraction":"none","config_keys":[]},"tsconfig.json":{"id":"can://slim/artifact/tsconfig.json","kind":"artifact","path":"tsconfig.json","format":"json","roles":["tool-config"],"size_bytes":289,"sha256":"72f24fc616456ab556dd8e7c886264214cb344547b32b972eb476467af0a9cab","source":"{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"experimentalDecorators\": true,\n \"emitDecoratorMetadata\": true\n },\n \"include\": [\"src/**/*.ts\"]\n}\n","extraction":"full","config_keys":[{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.target","key":"compilerOptions.target","namespace":"json","value":"ES2022","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.module","key":"compilerOptions.module","namespace":"json","value":"ESNext","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.moduleResolution","key":"compilerOptions.moduleResolution","namespace":"json","value":"bundler","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.strict","key":"compilerOptions.strict","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.esModuleInterop","key":"compilerOptions.esModuleInterop","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.skipLibCheck","key":"compilerOptions.skipLibCheck","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.experimentalDecorators","key":"compilerOptions.experimentalDecorators","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.emitDecoratorMetadata","key":"compilerOptions.emitDecoratorMetadata","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/include.0","key":"include.0","namespace":"json","value":"src/**/*.ts","references":[]}]}},"dependencies":[],"unresolved_imports":[],"config_uses":[],"config_reads":[],"entrypoint_report":{"frameworks_detected":[],"rulesets":["shipped"],"unresolved":{"Get":2,"Controller":1},"errors":[]},"external_symbols":{"can://slim/@external/(builtin)/log":{"id":"can://slim/@external/(builtin)/log","kind":"external","module":"(builtin)","name":"log"},"can://slim/@external/(builtin)/push":{"id":"can://slim/@external/(builtin)/push","kind":"external","module":"(builtin)","name":"push"},"can://slim/@external/(builtin)/map":{"id":"can://slim/@external/(builtin)/map","kind":"external","module":"(builtin)","name":"map"},"can://slim/@external/(builtin)/charAt":{"id":"can://slim/@external/(builtin)/charAt","kind":"external","module":"(builtin)","name":"charAt"},"can://slim/@external/(builtin)/repeat":{"id":"can://slim/@external/(builtin)/repeat","kind":"external","module":"(builtin)","name":"repeat"},"can://slim/@external/(builtin)/replace":{"id":"can://slim/@external/(builtin)/replace","kind":"external","module":"(builtin)","name":"replace"},"can://slim/@external/(builtin)/toLowerCase":{"id":"can://slim/@external/(builtin)/toLowerCase","kind":"external","module":"(builtin)","name":"toLowerCase"},"can://slim/@external/(builtin)/join":{"id":"can://slim/@external/(builtin)/join","kind":"external","module":"(builtin)","name":"join"}},"synthesized_callables":{"can://slim/typescript/src/controllers.ts/Controller@5:10":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Get@8:10":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Param@11:10":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"callable"},"can://slim/typescript/src/services.ts/UserService/describeAll@37:27":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"callable"}}}} \ No newline at end of file +{"schema_version":"2.0.0","language":"typescript","max_level":3,"k_limit":3,"analyzer":{"name":"codeanalyzer-typescript","version":"1.6.0"},"application":{"id":"can://slim","kind":"application","symbol_table":{"src/controllers.ts":{"id":"can://slim/typescript/src/controllers.ts","kind":"module","span":{"start":[1,1],"end":[29,1],"bytes":[0,699]},"source":"import { UserService } from \"./services\";\n\n// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.\nfunction Controller(prefix: string): ClassDecorator {\n return () => undefined;\n}\nfunction Get(path: string): MethodDecorator {\n return () => undefined;\n}\nfunction Param(name: string): ParameterDecorator {\n return () => undefined;\n}\n\n@Controller(\"/users\")\nexport class UserController {\n constructor(private readonly service: UserService) {}\n\n @Get(\"/:id\")\n show(@Param(\"id\") id: string): string {\n const user = this.service.create(id);\n return user.describe();\n }\n\n @Get(\"/\")\n list(): string[] {\n return this.service.describeAll();\n }\n}\n","imports":[{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":42,"resolved_module":"src/services.ts"}],"exports":[],"comments":[{"content":"// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.","is_docstring":false,"start_line":3,"end_line":3,"start_column":1,"end_column":101}],"types":{"UserController":{"id":"can://slim/typescript/src/controllers.ts/UserController","kind":"class","span":{"start":[14,1],"end":[28,2],"bytes":[380,698]},"name":"UserController","signature":"src/controllers.UserController","comments":[],"decorators":[{"name":"Controller","positional_arguments":["\"/users\""],"keyword_arguments":{},"start_line":14,"end_line":14,"start_column":1,"end_column":22}],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"show":{"id":"can://slim/typescript/src/controllers.ts/UserController/show","kind":"method","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"name":"show","signature":"src/controllers.UserController.show","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/:id\""],"keyword_arguments":{},"start_line":18,"end_line":18,"start_column":3,"end_column":15}],"parameters":[{"name":"id","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[{"name":"Param","positional_arguments":["\"id\""],"keyword_arguments":{},"start_line":19,"end_line":19,"start_column":8,"end_column":20}],"start_line":19,"end_line":19,"start_column":8,"end_column":31,"id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"20:18":{"kind":"call","span":{"start":[20,18],"end":[20,41],"bytes":[563,586]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this.service","receiver_type":"UserService","argument_types":["string"],"type_arguments":[],"return_type":"import(\"./models\").User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:18"},"21:12":{"kind":"call","span":{"start":[21,12],"end":[21,27],"bytes":[599,614]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"user","receiver_type":"import(\"./models\").User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:12"},"19:9":{"kind":"call","span":{"start":[19,9],"end":[19,20],"bytes":[512,523]},"callee":"can://slim/typescript/src/controllers.ts/Param","method_name":"Param","argument_types":["\"id\""],"type_arguments":[],"return_type":"ParameterDecorator","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@19:9"},"@entry":{"kind":"entry","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@entry"},"20:5":{"kind":"statement","span":{"start":[20,5],"end":[20,42],"bytes":[550,587]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:5"},"21:5":{"kind":"statement","span":{"start":[21,5],"end":[21,28],"bytes":[592,615]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:5"},"@exit":{"kind":"exit","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"20:5","kind":"fallthrough"},{"src":"20:5","dst":"@exit","kind":"exception"},{"src":"20:5","dst":"21:5","kind":"fallthrough"},{"src":"21:5","dst":"@exit","kind":"exception"},{"src":"21:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"20:5"},{"src":"20:5","dst":"21:5"}],"ddg":[{"src":"@entry","dst":"20:5","var":"id","prov":["reaching-defs"]},{"src":"@entry","dst":"20:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"20:5","var":"this.service.create","prov":["reaching-defs"]},{"src":"20:5","dst":"21:5","var":"user.describe","prov":["reaching-defs"]}]},"list":{"id":"can://slim/typescript/src/controllers.ts/UserController/list","kind":"method","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"name":"list","signature":"src/controllers.UserController.list","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/\""],"keyword_arguments":{},"start_line":24,"end_line":24,"start_column":3,"end_column":12}],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,38],"bytes":[665,691]},"callee":"can://slim/typescript/src/services.ts/UserService/describeAll","method_name":"describeAll","receiver_expr":"this.service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:12"},"@entry":{"kind":"entry","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@entry"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,39],"bytes":[658,692]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:5"},"@exit":{"kind":"exit","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"26:5"}],"ddg":[{"src":"@entry","dst":"26:5","var":"this.service.describeAll","prov":["reaching-defs"]}]},"constructor":{"id":"can://slim/typescript/src/controllers.ts/UserController/constructor","kind":"constructor","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"name":"constructor","signature":"src/controllers.UserController.constructor","comments":[],"decorators":[],"parameters":[{"name":"service","type":"UserService","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":16,"end_line":16,"start_column":15,"end_column":52,"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[]}},"fields":{"service":{"id":"can://slim/typescript/src/controllers.ts/UserController/service","kind":"field","name":"service","type":"UserService","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"Controller":{"id":"can://slim/typescript/src/controllers.ts/Controller","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"name":"Controller","signature":"src/controllers.Controller","comments":[],"decorators":[],"parameters":[{"name":"prefix","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":21,"end_column":35,"id":"can://slim/typescript/src/controllers.ts/Controller@formal_in:0"}],"type_parameters":[],"return_type":"ClassDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"id":"can://slim/typescript/src/controllers.ts/Controller@entry"},"5:3":{"kind":"statement","span":{"start":[5,3],"end":[5,26],"bytes":[200,223]},"id":"can://slim/typescript/src/controllers.ts/Controller@5:3"},"@exit":{"kind":"exit","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"id":"can://slim/typescript/src/controllers.ts/Controller@exit"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"arrow","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"name":"(anonymous)","signature":"src/controllers.Controller.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@entry"},"5:16":{"kind":"statement","span":{"start":[5,16],"end":[5,25],"bytes":[213,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@5:16"},"@exit":{"kind":"exit","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:16","kind":"fallthrough"},{"src":"5:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:16"}],"ddg":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:3","kind":"fallthrough"},{"src":"5:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:3"}],"ddg":[]},"Get":{"id":"can://slim/typescript/src/controllers.ts/Get","kind":"function","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"name":"Get","signature":"src/controllers.Get","comments":[],"decorators":[],"parameters":[{"name":"path","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":14,"end_column":26,"id":"can://slim/typescript/src/controllers.ts/Get@formal_in:0"}],"type_parameters":[],"return_type":"MethodDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"id":"can://slim/typescript/src/controllers.ts/Get@entry"},"8:3":{"kind":"statement","span":{"start":[8,3],"end":[8,26],"bytes":[274,297]},"id":"can://slim/typescript/src/controllers.ts/Get@8:3"},"@exit":{"kind":"exit","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"id":"can://slim/typescript/src/controllers.ts/Get@exit"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"arrow","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"name":"(anonymous)","signature":"src/controllers.Get.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@entry"},"8:16":{"kind":"statement","span":{"start":[8,16],"end":[8,25],"bytes":[287,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@8:16"},"@exit":{"kind":"exit","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:16","kind":"fallthrough"},{"src":"8:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:16"}],"ddg":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:3","kind":"fallthrough"},{"src":"8:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:3"}],"ddg":[]},"Param":{"id":"can://slim/typescript/src/controllers.ts/Param","kind":"function","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"name":"Param","signature":"src/controllers.Param","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":10,"end_line":10,"start_column":16,"end_column":28,"id":"can://slim/typescript/src/controllers.ts/Param@formal_in:0"}],"type_parameters":[],"return_type":"ParameterDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"id":"can://slim/typescript/src/controllers.ts/Param@entry"},"11:3":{"kind":"statement","span":{"start":[11,3],"end":[11,26],"bytes":[353,376]},"id":"can://slim/typescript/src/controllers.ts/Param@11:3"},"@exit":{"kind":"exit","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"id":"can://slim/typescript/src/controllers.ts/Param@exit"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"arrow","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"name":"(anonymous)","signature":"src/controllers.Param.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@entry"},"11:16":{"kind":"statement","span":{"start":[11,16],"end":[11,25],"bytes":[366,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@11:16"},"@exit":{"kind":"exit","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"11:16","kind":"fallthrough"},{"src":"11:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"11:16"}],"ddg":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"11:3","kind":"fallthrough"},{"src":"11:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"11:3"}],"ddg":[]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d42b8f615d51575e3436409b9fce70862182b6071da40471b4be9b95f7c9ee4c"},"src/index.ts":{"id":"can://slim/typescript/src/index.ts","kind":"module","span":{"start":[1,1],"end":[26,1],"bytes":[0,742]},"source":"import { UserController } from \"./controllers\";\nimport { Robot, Role, User } from \"./models\";\nimport { UserService, announce } from \"./services\";\nimport { StringUtil } from \"./util\";\n\nexport function main(): void {\n const service = new UserService(100);\n service.create(\"Ada\", Role.Admin);\n service.createGuest();\n\n const controller = new UserController(service);\n controller.list();\n controller.show(\"42\");\n\n // interface-typed dispatch — RTA should expand announce -> {User,Robot}.describe\n announce(new User(1, \"Ada\", Role.Admin));\n announce(new Robot(\"r2d2\"));\n\n const slug = StringUtil.repeat(\"hello world\", 2);\n const builder = new StringUtil.Builder();\n builder.add(\"a\").add(\"b\").build();\n console.log(slug);\n}\n\nmain();\n","imports":[{"module":"./controllers","name":"UserController","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":48,"resolved_module":"src/controllers.ts"},{"module":"./models","name":"Robot","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./services","name":"announce","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./util","name":"StringUtil","is_type_only":false,"import_kind":"named","start_line":4,"end_line":4,"start_column":1,"end_column":37,"resolved_module":"src/util.ts"}],"exports":[],"comments":[],"types":{},"functions":{"main":{"id":"can://slim/typescript/src/index.ts/main","kind":"function","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"name":"main","signature":"src/index.main","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"void","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"7:19":{"kind":"call","span":{"start":[7,19],"end":[7,39],"bytes":[233,253]},"callee":"can://slim/typescript/src/services.ts/UserService/constructor","method_name":"UserService","argument_types":["100"],"type_arguments":[],"return_type":"UserService","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@7:19"},"8:3":{"kind":"call","span":{"start":[8,3],"end":[8,36],"bytes":[257,290]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"service","receiver_type":"UserService","argument_types":["\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@8:3"},"9:3":{"kind":"call","span":{"start":[9,3],"end":[9,24],"bytes":[294,315]},"callee":"can://slim/typescript/src/services.ts/UserService/createGuest","method_name":"createGuest","receiver_expr":"service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@9:3"},"11:22":{"kind":"call","span":{"start":[11,22],"end":[11,49],"bytes":[339,366]},"callee":"can://slim/typescript/src/controllers.ts/UserController/constructor","method_name":"UserController","argument_types":["UserService"],"type_arguments":[],"return_type":"UserController","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@11:22"},"12:3":{"kind":"call","span":{"start":[12,3],"end":[12,20],"bytes":[370,387]},"callee":"can://slim/typescript/src/controllers.ts/UserController/list","method_name":"list","receiver_expr":"controller","receiver_type":"UserController","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@12:3"},"13:3":{"kind":"call","span":{"start":[13,3],"end":[13,24],"bytes":[391,412]},"callee":"can://slim/typescript/src/controllers.ts/UserController/show","method_name":"show","receiver_expr":"controller","receiver_type":"UserController","argument_types":["\"42\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@13:3"},"16:3":{"kind":"call","span":{"start":[16,3],"end":[16,43],"bytes":[503,543]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["User"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:3"},"16:12":{"kind":"call","span":{"start":[16,12],"end":[16,42],"bytes":[512,542]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["1","\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:12"},"17:3":{"kind":"call","span":{"start":[17,3],"end":[17,30],"bytes":[547,574]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["Robot"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:3"},"17:12":{"kind":"call","span":{"start":[17,12],"end":[17,29],"bytes":[556,573]},"callee":"can://slim/typescript/src/models.ts/Robot/constructor","method_name":"Robot","argument_types":["\"r2d2\""],"type_arguments":[],"return_type":"Robot","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:12"},"19:16":{"kind":"call","span":{"start":[19,16],"end":[19,51],"bytes":[592,627]},"callee":"can://slim/typescript/src/util.ts/StringUtil/repeat","method_name":"repeat","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":["\"hello world\"","2"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@19:16"},"20:19":{"kind":"call","span":{"start":[20,19],"end":[20,43],"bytes":[647,671]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","method_name":"Builder","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":[],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@20:19"},"21:3":{"kind":"call","span":{"start":[21,3],"end":[21,36],"bytes":[675,708]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","method_name":"build","receiver_expr":"builder.add(\"a\").add(\"b\")","receiver_type":"StringUtil.Builder","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3"},"21:3/2":{"kind":"call","span":{"start":[21,3],"end":[21,28],"bytes":[675,700]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder.add(\"a\")","receiver_type":"StringUtil.Builder","argument_types":["\"b\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/2"},"21:3/3":{"kind":"call","span":{"start":[21,3],"end":[21,19],"bytes":[675,691]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder","receiver_type":"StringUtil.Builder","argument_types":["\"a\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/3"},"22:3":{"kind":"call","span":{"start":[22,3],"end":[22,20],"bytes":[712,729]},"callee":"can://slim/@external/(builtin)/log","method_name":"log","receiver_expr":"console","receiver_type":"Console","argument_types":["string"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@22:3"},"@entry":{"kind":"entry","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"id":"can://slim/typescript/src/index.ts/main@entry"},"7:3":{"kind":"statement","span":{"start":[7,3],"end":[7,40],"bytes":[217,254]},"id":"can://slim/typescript/src/index.ts/main@7:3"},"11:3":{"kind":"statement","span":{"start":[11,3],"end":[11,50],"bytes":[320,367]},"id":"can://slim/typescript/src/index.ts/main@11:3"},"19:3":{"kind":"statement","span":{"start":[19,3],"end":[19,52],"bytes":[579,628]},"id":"can://slim/typescript/src/index.ts/main@19:3"},"20:3":{"kind":"statement","span":{"start":[20,3],"end":[20,44],"bytes":[631,672]},"id":"can://slim/typescript/src/index.ts/main@20:3"},"@exit":{"kind":"exit","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"id":"can://slim/typescript/src/index.ts/main@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"7:3","kind":"fallthrough"},{"src":"11:3","dst":"@exit","kind":"exception"},{"src":"11:3","dst":"12:3","kind":"fallthrough"},{"src":"12:3","dst":"@exit","kind":"exception"},{"src":"12:3","dst":"13:3","kind":"fallthrough"},{"src":"13:3","dst":"@exit","kind":"exception"},{"src":"13:3","dst":"16:3","kind":"fallthrough"},{"src":"16:3","dst":"@exit","kind":"exception"},{"src":"16:3","dst":"17:3","kind":"fallthrough"},{"src":"17:3","dst":"@exit","kind":"exception"},{"src":"17:3","dst":"19:3","kind":"fallthrough"},{"src":"19:3","dst":"@exit","kind":"exception"},{"src":"19:3","dst":"20:3","kind":"fallthrough"},{"src":"20:3","dst":"@exit","kind":"exception"},{"src":"20:3","dst":"21:3","kind":"fallthrough"},{"src":"21:3","dst":"@exit","kind":"exception"},{"src":"21:3","dst":"22:3","kind":"fallthrough"},{"src":"22:3","dst":"@exit","kind":"exception"},{"src":"22:3","dst":"@exit","kind":"fallthrough"},{"src":"7:3","dst":"@exit","kind":"exception"},{"src":"7:3","dst":"8:3","kind":"fallthrough"},{"src":"8:3","dst":"@exit","kind":"exception"},{"src":"8:3","dst":"9:3","kind":"fallthrough"},{"src":"9:3","dst":"@exit","kind":"exception"},{"src":"9:3","dst":"11:3","kind":"fallthrough"}],"cdg":[{"src":"@entry","dst":"7:3"},{"src":"11:3","dst":"12:3"},{"src":"12:3","dst":"13:3"},{"src":"13:3","dst":"16:3"},{"src":"16:3","dst":"17:3"},{"src":"17:3","dst":"19:3"},{"src":"19:3","dst":"20:3"},{"src":"20:3","dst":"21:3"},{"src":"21:3","dst":"22:3"},{"src":"7:3","dst":"8:3"},{"src":"8:3","dst":"9:3"},{"src":"9:3","dst":"11:3"}],"ddg":[{"src":"@entry","dst":"13:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"8:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"9:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"11:3","dst":"12:3","var":"controller.list","prov":["reaching-defs"]},{"src":"11:3","dst":"13:3","var":"controller.show","prov":["reaching-defs"]},{"src":"19:3","dst":"22:3","var":"slug","prov":["reaching-defs"]},{"src":"20:3","dst":"21:3","var":"builder.add","prov":["reaching-defs"]},{"src":"7:3","dst":"11:3","var":"service","prov":["reaching-defs"]},{"src":"7:3","dst":"8:3","var":"service.create","prov":["reaching-defs"]},{"src":"7:3","dst":"9:3","var":"service.createGuest","prov":["reaching-defs"]}]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"6de6f6ff5a01a5c7c750a93d5e10bae7b15817f386421f45c7527cfb7259d9b3"},"src/models.ts":{"id":"can://slim/typescript/src/models.ts","kind":"module","span":{"start":[1,1],"end":[65,1],"bytes":[0,1237]},"source":"/** Domain models for the sample app. */\n\nexport interface Identifiable {\n readonly id: T;\n}\n\nexport interface Named {\n name: string;\n describe(): string;\n}\n\nexport type UserId = string | number;\n\nexport enum Role {\n Admin = \"admin\",\n Member = \"member\",\n Guest = \"guest\",\n}\n\nexport const enum Flag {\n None = 0,\n Active = 1,\n}\n\n/** A user of the system. */\nexport abstract class Entity implements Identifiable {\n constructor(public readonly id: ID) {}\n abstract describe(): string;\n}\n\nexport class User extends Entity implements Named {\n private loginCount = 0;\n static instances = 0;\n\n constructor(\n id: UserId,\n public name: string,\n private role: Role = Role.Member,\n ) {\n super(id);\n User.instances++;\n }\n\n get isAdmin(): boolean {\n return this.role === Role.Admin;\n }\n\n describe(): string {\n return `${this.name} (${this.role})`;\n }\n\n async recordLogin(): Promise {\n this.loginCount += 1;\n return this.loginCount;\n }\n}\n\n/** A second, unrelated implementer of Named — drives RTA subtype expansion. */\nexport class Robot implements Named {\n constructor(public name: string) {}\n describe(): string {\n return `robot:${this.name}`;\n }\n}\n","imports":[],"exports":[],"comments":[{"content":"/** Domain models for the sample app. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41},{"content":"/** A user of the system. */","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29},{"content":"/** A second, unrelated implementer of Named — drives RTA subtype expansion. */","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"types":{"Entity":{"id":"can://slim/typescript/src/models.ts/Entity","kind":"class","span":{"start":[26,1],"end":[29,2],"bytes":[376,521]},"name":"Entity","signature":"src/models.Entity","comments":[{"content":"A user of the system.","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29}],"decorators":[],"base_classes":["src/models.Identifiable"],"implements_types":["src/models.Identifiable"],"type_parameters":[{"name":"ID","default":"string"}],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Entity/describe","kind":"method","span":{"start":[28,3],"end":[28,31],"bytes":[491,519]},"name":"describe","signature":"src/models.Entity.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":true,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[{"parameters":[],"return_type":"string","type_parameters":[],"start_line":28,"end_line":28}],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Entity/constructor","kind":"constructor","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"name":"constructor","signature":"src/models.Entity.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"ID","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"public","decorators":[],"start_line":27,"end_line":27,"start_column":15,"end_column":37,"id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"id":"can://slim/typescript/src/models.ts/Entity/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"id":"can://slim/typescript/src/models.ts/Entity/constructor@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[]}},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Entity/id","kind":"field","name":"id","type":"ID","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":true,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Identifiable"],"entrypoints":[],"is_entrypoint":false},"User":{"id":"can://slim/typescript/src/models.ts/User","kind":"class","span":{"start":[31,1],"end":[56,2],"bytes":[523,1015]},"name":"User","signature":"src/models.User","comments":[],"decorators":[],"base_classes":["src/models.Entity","src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/User/describe","kind":"method","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"name":"describe","signature":"src/models.User.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"id":"can://slim/typescript/src/models.ts/User/describe@entry"},"49:5":{"kind":"statement","span":{"start":[49,5],"end":[49,42],"bytes":[872,909]},"id":"can://slim/typescript/src/models.ts/User/describe@49:5"},"@exit":{"kind":"exit","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"id":"can://slim/typescript/src/models.ts/User/describe@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"49:5","kind":"fallthrough"},{"src":"49:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"49:5"}],"ddg":[{"src":"@entry","dst":"49:5","var":"this.name","prov":["reaching-defs"]},{"src":"@entry","dst":"49:5","var":"this.role","prov":["reaching-defs"]}]},"recordLogin":{"id":"can://slim/typescript/src/models.ts/User/recordLogin","kind":"method","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"name":"recordLogin","signature":"src/models.User.recordLogin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@entry"},"53:5":{"kind":"statement","span":{"start":[53,5],"end":[53,26],"bytes":[960,981]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@53:5"},"54:5":{"kind":"statement","span":{"start":[54,5],"end":[54,28],"bytes":[986,1009]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@54:5"},"@exit":{"kind":"exit","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"53:5","kind":"fallthrough"},{"src":"53:5","dst":"54:5","kind":"fallthrough"},{"src":"54:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"53:5"},{"src":"@entry","dst":"54:5"}],"ddg":[{"src":"@entry","dst":"53:5","var":"this.loginCount","prov":["reaching-defs"]},{"src":"@entry","dst":"54:5","var":"this.loginCount","prov":["reaching-defs"]},{"src":"53:5","dst":"54:5","var":"this.loginCount","prov":["reaching-defs"]}]},"constructor":{"id":"can://slim/typescript/src/models.ts/User/constructor","kind":"constructor","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"name":"constructor","signature":"src/models.User.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"UserId","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":36,"end_line":36,"start_column":5,"end_column":15,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0"},{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":37,"end_line":37,"start_column":5,"end_column":24,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"accessibility":"private","decorators":[],"start_line":38,"end_line":38,"start_column":5,"end_column":37,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"40:5":{"kind":"call","span":{"start":[40,5],"end":[40,14],"bytes":[738,747]},"callee":"can://slim/typescript/src/models.ts/Entity/constructor","method_name":"super","argument_types":["UserId"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/models.ts/User/constructor@40:5"},"@entry":{"kind":"entry","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"id":"can://slim/typescript/src/models.ts/User/constructor@entry"},"41:5":{"kind":"statement","span":{"start":[41,5],"end":[41,22],"bytes":[753,770]},"id":"can://slim/typescript/src/models.ts/User/constructor@41:5"},"@exit":{"kind":"exit","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"id":"can://slim/typescript/src/models.ts/User/constructor@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"40:5","kind":"fallthrough"},{"src":"40:5","dst":"@exit","kind":"exception"},{"src":"40:5","dst":"41:5","kind":"fallthrough"},{"src":"41:5","dst":"@exit","kind":"fallthrough"}],"cdg":[{"src":"@entry","dst":"40:5"},{"src":"40:5","dst":"41:5"}],"ddg":[{"src":"@entry","dst":"40:5","var":"id","prov":["reaching-defs"]}]},"isAdmin#get":{"id":"can://slim/typescript/src/models.ts/User/isAdmin","kind":"getter","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"name":"isAdmin","signature":"src/models.User.isAdmin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"boolean","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"accessor_kind":"getter","overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@entry"},"45:5":{"kind":"statement","span":{"start":[45,5],"end":[45,37],"bytes":[807,839]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@45:5"},"@exit":{"kind":"exit","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"45:5","kind":"fallthrough"},{"src":"45:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"45:5"}],"ddg":[{"src":"@entry","dst":"45:5","var":"this.role","prov":["reaching-defs"]}]}},"fields":{"loginCount":{"id":"can://slim/typescript/src/models.ts/User/loginCount","kind":"field","span":{"start":[32,3],"end":[32,26],"bytes":[585,608]},"name":"loginCount","type":"number","comments":[],"decorators":[],"initializer":"0","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"instances":{"id":"can://slim/typescript/src/models.ts/User/instances","kind":"field","span":{"start":[33,3],"end":[33,24],"bytes":[611,632]},"name":"instances","type":"number","comments":[],"decorators":[],"initializer":"0","is_static":true,"is_readonly":false,"is_optional":false,"is_abstract":false},"name":{"id":"can://slim/typescript/src/models.ts/User/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"role":{"id":"can://slim/typescript/src/models.ts/User/role","kind":"field","name":"role","type":"Role","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":false,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"extends_ids":["can://slim/typescript/src/models.ts/Entity"],"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Robot":{"id":"can://slim/typescript/src/models.ts/Robot","kind":"class","span":{"start":[59,1],"end":[64,2],"bytes":[1099,1236]},"name":"Robot","signature":"src/models.Robot","comments":[{"content":"A second, unrelated implementer of Named — drives RTA subtype expansion.","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"decorators":[],"base_classes":["src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Robot/describe","kind":"method","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"name":"describe","signature":"src/models.Robot.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"id":"can://slim/typescript/src/models.ts/Robot/describe@entry"},"62:5":{"kind":"statement","span":{"start":[62,5],"end":[62,33],"bytes":[1202,1230]},"id":"can://slim/typescript/src/models.ts/Robot/describe@62:5"},"@exit":{"kind":"exit","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"id":"can://slim/typescript/src/models.ts/Robot/describe@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"62:5","kind":"fallthrough"},{"src":"62:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"62:5"}],"ddg":[{"src":"@entry","dst":"62:5","var":"this.name","prov":["reaching-defs"]}]},"constructor":{"id":"can://slim/typescript/src/models.ts/Robot/constructor","kind":"constructor","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"name":"constructor","signature":"src/models.Robot.constructor","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":60,"end_line":60,"start_column":15,"end_column":34,"id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"id":"can://slim/typescript/src/models.ts/Robot/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"id":"can://slim/typescript/src/models.ts/Robot/constructor@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[]}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Robot/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Identifiable":{"id":"can://slim/typescript/src/models.ts/Identifiable","kind":"interface","span":{"start":[3,1],"end":[5,2],"bytes":[42,105]},"name":"Identifiable","signature":"src/models.Identifiable","comments":[{"content":"Domain models for the sample app.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41}],"base_classes":[],"type_parameters":[{"name":"T","default":"string"}],"callables":{},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Identifiable/id","kind":"field","span":{"start":[4,3],"end":[4,18],"bytes":[88,103]},"name":"id","type":"T","comments":[],"decorators":[],"is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Named":{"id":"can://slim/typescript/src/models.ts/Named","kind":"interface","span":{"start":[7,1],"end":[10,2],"bytes":[107,171]},"name":"Named","signature":"src/models.Named","comments":[],"base_classes":[],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Named/describe","kind":"method","span":{"start":[9,3],"end":[9,22],"bytes":[150,169]},"name":"describe","signature":"src/models.Named.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Named/name","kind":"field","span":{"start":[8,3],"end":[8,16],"bytes":[134,147]},"name":"name","type":"string","comments":[],"decorators":[],"is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Role":{"id":"can://slim/typescript/src/models.ts/Role","kind":"enum","span":{"start":[14,1],"end":[18,2],"bytes":[212,291]},"name":"Role","signature":"src/models.Role","comments":[],"fields":{"Admin":{"id":"can://slim/typescript/src/models.ts/Role/Admin","kind":"field","span":{"start":[15,3],"end":[15,18],"bytes":[233,248]},"name":"Admin","value":"admin"},"Member":{"id":"can://slim/typescript/src/models.ts/Role/Member","kind":"field","span":{"start":[16,3],"end":[16,20],"bytes":[252,269]},"name":"Member","value":"member"},"Guest":{"id":"can://slim/typescript/src/models.ts/Role/Guest","kind":"field","span":{"start":[17,3],"end":[17,18],"bytes":[273,288]},"name":"Guest","value":"guest"}},"is_const":false,"is_exported":true,"is_ambient":false},"Flag":{"id":"can://slim/typescript/src/models.ts/Flag","kind":"enum","span":{"start":[20,1],"end":[23,2],"bytes":[293,345]},"name":"Flag","signature":"src/models.Flag","comments":[],"fields":{"None":{"id":"can://slim/typescript/src/models.ts/Flag/None","kind":"field","span":{"start":[21,3],"end":[21,11],"bytes":[320,328]},"name":"None","value":"0"},"Active":{"id":"can://slim/typescript/src/models.ts/Flag/Active","kind":"field","span":{"start":[22,3],"end":[22,13],"bytes":[332,342]},"name":"Active","value":"1"}},"is_const":true,"is_exported":true,"is_ambient":false},"UserId":{"id":"can://slim/typescript/src/models.ts/UserId","kind":"type_alias","span":{"start":[12,1],"end":[12,38],"bytes":[173,210]},"name":"UserId","signature":"src/models.UserId","comments":[],"aliased_type":"string | number","type_parameters":[],"is_exported":true,"is_ambient":false}},"functions":{},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d39ff571ccfda4b7c46923586b6b94d0e818a51be966f1ba40305650fd0ffc91"},"src/services.ts":{"id":"can://slim/typescript/src/services.ts","kind":"module","span":{"start":[1,1],"end":[48,1],"bytes":[0,1240]},"source":"import { type Named, Role, User, type UserId } from \"./models\";\n\n/** Pure helper — top-level function. */\nexport function makeGuestName(seed: number): string {\n return `guest-${seed}`;\n}\n\n/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */\nexport function announce(thing: Named): string {\n return thing.describe();\n}\n\n/** Arrow function bound to a const (function_expression-style callable). */\nexport const nextId = (n: number): UserId => n + 1;\n\nexport class UserService {\n private users: User[] = [];\n\n constructor(private readonly startId: number = 0) {}\n\n create(name: string, role: Role = Role.Member): User {\n const id = nextId(this.users.length + this.startId);\n const user = new User(id, name, role);\n this.users.push(user);\n return user;\n }\n\n createGuest(): User {\n const name = makeGuestName(this.users.length);\n return this.create(name, Role.Guest);\n }\n\n describeAll(): string[] {\n return this.users.map((u) => u.describe());\n }\n\n async loginAll(): Promise {\n let total = 0;\n for (const u of this.users) {\n total += await u.recordLogin();\n }\n return total;\n }\n}\n","imports":[{"module":"./models","name":"Named","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"UserId","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"}],"exports":[],"comments":[{"content":"/** Pure helper — top-level function. */","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41},{"content":"/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4},{"content":"/** Arrow function bound to a const (function_expression-style callable). */","is_docstring":true,"start_line":16,"end_line":16,"start_column":1,"end_column":77}],"types":{"UserService":{"id":"can://slim/typescript/src/services.ts/UserService","kind":"class","span":{"start":[19,1],"end":[47,2],"bytes":[558,1239]},"name":"UserService","signature":"src/services.UserService","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"create":{"id":"can://slim/typescript/src/services.ts/UserService/create","kind":"method","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"name":"create","signature":"src/services.UserService.create","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":10,"end_column":22,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":24,"end_column":48,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1"}],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"25:16":{"kind":"call","span":{"start":[25,16],"end":[25,56],"bytes":[744,784]},"callee":"can://slim/typescript/src/services.ts/nextId","method_name":"nextId","argument_types":["number"],"type_arguments":[],"return_type":"UserId","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@25:16"},"26:18":{"kind":"call","span":{"start":[26,18],"end":[26,42],"bytes":[803,827]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["UserId","string","Role"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@26:18"},"27:5":{"kind":"call","span":{"start":[27,5],"end":[27,26],"bytes":[833,854]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["User"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@27:5"},"@entry":{"kind":"entry","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"id":"can://slim/typescript/src/services.ts/UserService/create@entry"},"25:5":{"kind":"statement","span":{"start":[25,5],"end":[25,57],"bytes":[733,785]},"id":"can://slim/typescript/src/services.ts/UserService/create@25:5"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,43],"bytes":[790,828]},"id":"can://slim/typescript/src/services.ts/UserService/create@26:5"},"28:5":{"kind":"statement","span":{"start":[28,5],"end":[28,17],"bytes":[860,872]},"id":"can://slim/typescript/src/services.ts/UserService/create@28:5"},"@exit":{"kind":"exit","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"id":"can://slim/typescript/src/services.ts/UserService/create@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"25:5","kind":"fallthrough"},{"src":"25:5","dst":"@exit","kind":"exception"},{"src":"25:5","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"27:5","kind":"fallthrough"},{"src":"27:5","dst":"@exit","kind":"exception"},{"src":"27:5","dst":"28:5","kind":"fallthrough"},{"src":"28:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"25:5"},{"src":"25:5","dst":"26:5"},{"src":"26:5","dst":"27:5"},{"src":"27:5","dst":"28:5"}],"ddg":[{"src":"@entry","dst":"25:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5","var":"this.startId","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"26:5","var":"name","prov":["reaching-defs"]},{"src":"@entry","dst":"26:5","var":"role","prov":["reaching-defs"]},{"src":"@entry","dst":"27:5","var":"this.users.push","prov":["reaching-defs"]},{"src":"25:5","dst":"26:5","var":"id","prov":["reaching-defs"]},{"src":"26:5","dst":"27:5","var":"user","prov":["reaching-defs"]},{"src":"26:5","dst":"28:5","var":"user","prov":["reaching-defs"]}]},"createGuest":{"id":"can://slim/typescript/src/services.ts/UserService/createGuest","kind":"method","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"name":"createGuest","signature":"src/services.UserService.createGuest","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"32:18":{"kind":"call","span":{"start":[32,18],"end":[32,50],"bytes":[919,951]},"callee":"can://slim/typescript/src/services.ts/makeGuestName","method_name":"makeGuestName","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:18"},"33:12":{"kind":"call","span":{"start":[33,12],"end":[33,41],"bytes":[964,993]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this","receiver_type":"this","argument_types":["string","Role.Guest"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:12"},"@entry":{"kind":"entry","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@entry"},"32:5":{"kind":"statement","span":{"start":[32,5],"end":[32,51],"bytes":[906,952]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5"},"33:5":{"kind":"statement","span":{"start":[33,5],"end":[33,42],"bytes":[957,994]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5"},"@exit":{"kind":"exit","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"32:5","kind":"fallthrough"},{"src":"32:5","dst":"@exit","kind":"exception"},{"src":"32:5","dst":"33:5","kind":"fallthrough"},{"src":"33:5","dst":"@exit","kind":"exception"},{"src":"33:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"32:5"},{"src":"32:5","dst":"33:5"}],"ddg":[{"src":"@entry","dst":"32:5","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"33:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"33:5","var":"this.create","prov":["reaching-defs"]},{"src":"32:5","dst":"33:5","var":"name","prov":["reaching-defs"]}]},"describeAll":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll","kind":"method","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"name":"describeAll","signature":"src/services.UserService.describeAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:12":{"kind":"call","span":{"start":[37,12],"end":[37,47],"bytes":[1039,1074]},"callee":"can://slim/@external/(builtin)/map","method_name":"map","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["(u: User) => string"],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:12"},"@entry":{"kind":"entry","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@entry"},"37:5":{"kind":"statement","span":{"start":[37,5],"end":[37,48],"bytes":[1032,1075]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:5"},"@exit":{"kind":"exit","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@exit"}},"callables":{"":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"arrow","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"name":"(anonymous)","signature":"src/services.UserService.describeAll.","comments":[],"decorators":[],"parameters":[{"name":"u","type":"User","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":37,"end_line":37,"start_column":28,"end_column":29,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:34":{"kind":"call","span":{"start":[37,34],"end":[37,46],"bytes":[1061,1073]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34"},"@entry":{"kind":"entry","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@entry"},"@exit":{"kind":"exit","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"37:34","kind":"fallthrough"},{"src":"37:34","dst":"@exit","kind":"exception"},{"src":"37:34","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"37:34"}],"ddg":[{"src":"@entry","dst":"37:34","var":"u.describe","prov":["reaching-defs"]}]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"37:5","kind":"fallthrough"},{"src":"37:5","dst":"@exit","kind":"exception"},{"src":"37:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"37:5"}],"ddg":[{"src":"@entry","dst":"37:5","var":"this.users.map","prov":["reaching-defs"]}]},"loginAll":{"id":"can://slim/typescript/src/services.ts/UserService/loginAll","kind":"method","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"name":"loginAll","signature":"src/services.UserService.loginAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"43:22":{"kind":"call","span":{"start":[43,22],"end":[43,37],"bytes":[1193,1208]},"callee":"can://slim/typescript/src/models.ts/User/recordLogin","method_name":"recordLogin","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"Promise","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:22"},"@entry":{"kind":"entry","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@entry"},"41:5":{"kind":"statement","span":{"start":[41,5],"end":[41,19],"bytes":[1123,1137]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@41:5"},"42:5":{"kind":"statement","span":{"start":[42,5],"end":[44,6],"bytes":[1142,1215]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@42:5"},"43:7":{"kind":"statement","span":{"start":[43,7],"end":[43,38],"bytes":[1178,1209]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:7"},"45:5":{"kind":"statement","span":{"start":[45,5],"end":[45,18],"bytes":[1220,1233]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@45:5"},"@exit":{"kind":"exit","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"41:5","kind":"fallthrough"},{"src":"41:5","dst":"42:5","kind":"fallthrough"},{"src":"42:5","dst":"43:7","kind":"true"},{"src":"42:5","dst":"45:5","kind":"false"},{"src":"43:7","dst":"@exit","kind":"exception"},{"src":"43:7","dst":"42:5","kind":"loop_back"},{"src":"45:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"41:5"},{"src":"@entry","dst":"42:5"},{"src":"42:5","dst":"43:7"},{"src":"42:5","dst":"45:5"},{"src":"43:7","dst":"42:5"}],"ddg":[{"src":"@entry","dst":"42:5","var":"this.users","prov":["reaching-defs"]},{"src":"41:5","dst":"43:7","var":"total","prov":["reaching-defs"]},{"src":"41:5","dst":"45:5","var":"total","prov":["reaching-defs"]},{"src":"42:5","dst":"43:7","var":"u.recordLogin","prov":["reaching-defs"]},{"src":"43:7","dst":"43:7","var":"total","prov":["reaching-defs"]},{"src":"43:7","dst":"45:5","var":"total","prov":["reaching-defs"]}]},"constructor":{"id":"can://slim/typescript/src/services.ts/UserService/constructor","kind":"constructor","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"name":"constructor","signature":"src/services.UserService.constructor","comments":[],"decorators":[],"parameters":[{"name":"startId","type":"number","default_value":"0","is_optional":true,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":22,"end_line":22,"start_column":15,"end_column":51,"id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"id":"can://slim/typescript/src/services.ts/UserService/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"id":"can://slim/typescript/src/services.ts/UserService/constructor@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[]}},"fields":{"users":{"id":"can://slim/typescript/src/services.ts/UserService/users","kind":"field","span":{"start":[20,3],"end":[20,30],"bytes":[587,614]},"name":"users","type":"User[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"startId":{"id":"can://slim/typescript/src/services.ts/UserService/startId","kind":"field","name":"startId","type":"number","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"makeGuestName":{"id":"can://slim/typescript/src/services.ts/makeGuestName","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"name":"makeGuestName","signature":"src/services.makeGuestName","comments":[{"content":"Pure helper — top-level function.","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41}],"decorators":[],"parameters":[{"name":"seed","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":31,"end_column":43,"id":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"id":"can://slim/typescript/src/services.ts/makeGuestName@entry"},"5:3":{"kind":"statement","span":{"start":[5,3],"end":[5,26],"bytes":[164,187]},"id":"can://slim/typescript/src/services.ts/makeGuestName@5:3"},"@exit":{"kind":"exit","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"id":"can://slim/typescript/src/services.ts/makeGuestName@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:3","kind":"fallthrough"},{"src":"5:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:3"}],"ddg":[{"src":"@entry","dst":"5:3","var":"seed","prov":["reaching-defs"]}]},"announce":{"id":"can://slim/typescript/src/services.ts/announce","kind":"function","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"name":"announce","signature":"src/services.announce","comments":[{"content":"Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\nconcrete implementer of Named (User, Robot, ...).","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4}],"decorators":[],"parameters":[{"name":"thing","type":"Named","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":12,"end_line":12,"start_column":26,"end_column":38,"id":"can://slim/typescript/src/services.ts/announce@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"13:10":{"kind":"call","span":{"start":[13,10],"end":[13,26],"bytes":[407,423]},"callee":"can://slim/typescript/src/models.ts/Named/describe","method_name":"describe","receiver_expr":"thing","receiver_type":"Named","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/announce@13:10"},"@entry":{"kind":"entry","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"id":"can://slim/typescript/src/services.ts/announce@entry"},"13:3":{"kind":"statement","span":{"start":[13,3],"end":[13,27],"bytes":[400,424]},"id":"can://slim/typescript/src/services.ts/announce@13:3"},"@exit":{"kind":"exit","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"id":"can://slim/typescript/src/services.ts/announce@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"13:3","kind":"fallthrough"},{"src":"13:3","dst":"@exit","kind":"exception"},{"src":"13:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"13:3"}],"ddg":[{"src":"@entry","dst":"13:3","var":"thing.describe","prov":["reaching-defs"]}]},"nextId":{"id":"can://slim/typescript/src/services.ts/nextId","kind":"arrow","span":{"start":[17,14],"end":[17,51],"bytes":[518,555]},"name":"nextId","signature":"src/services.nextId","comments":[],"decorators":[],"parameters":[{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":17,"end_line":17,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/services.ts/nextId@formal_in:0"}],"type_parameters":[],"return_type":"UserId","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[17,23],"end":[17,51],"bytes":[527,555]},"id":"can://slim/typescript/src/services.ts/nextId@entry"},"17:46":{"kind":"statement","span":{"start":[17,46],"end":[17,51],"bytes":[550,555]},"id":"can://slim/typescript/src/services.ts/nextId@17:46"},"@exit":{"kind":"exit","span":{"start":[17,23],"end":[17,51],"bytes":[527,555]},"id":"can://slim/typescript/src/services.ts/nextId@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"17:46","kind":"fallthrough"},{"src":"17:46","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"17:46"}],"ddg":[{"src":"@entry","dst":"17:46","var":"n","prov":["reaching-defs"]}]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"1bda3666dab48f8e686fb8ffc2143f2e422af62be46698053cfeea4184b55617"},"src/util.ts":{"id":"can://slim/typescript/src/util.ts","kind":"module","span":{"start":[1,1],"end":[35,1],"bytes":[0,949]},"source":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */\nexport namespace StringUtil {\n export function repeat(s: string, n: number): string {\n return slug(s).repeat(n);\n }\n\n export function slug(s: string): string {\n return s.toLowerCase().replace(/\\s+/g, \"-\");\n }\n\n export class Builder {\n private parts: string[] = [];\n add(part: string): this {\n this.parts.push(slug(part));\n return this;\n }\n build(): string {\n return this.parts.join(\"/\");\n }\n }\n}\n\n/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */\nexport function classify(items: T[]): Record {\n function keyOf(item: T): string {\n return item.name.charAt(0);\n }\n const out: Record = {};\n for (const item of items) {\n const k = keyOf(item);\n (out[k] ??= []).push(item);\n }\n return out;\n}\n","imports":[],"exports":[],"comments":[{"content":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106},{"content":"/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"types":{"StringUtil":{"id":"can://slim/typescript/src/util.ts/StringUtil","kind":"namespace","span":{"start":[2,1],"end":[21,2],"bytes":[106,543]},"name":"StringUtil","signature":"src/util.StringUtil","comments":[{"content":"A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106}],"types":{"Builder":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder","kind":"class","span":{"start":[11,3],"end":[20,4],"bytes":[328,541]},"name":"Builder","signature":"src/util.StringUtil.Builder","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"add":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","kind":"method","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"name":"add","signature":"src/util.StringUtil.Builder.add","comments":[],"decorators":[],"parameters":[{"name":"part","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":13,"end_line":13,"start_column":9,"end_column":21,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0"}],"type_parameters":[],"return_type":"this","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"14:7":{"kind":"call","span":{"start":[14,7],"end":[14,34],"bytes":[421,448]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["string"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7"},"14:23":{"kind":"call","span":{"start":[14,23],"end":[14,33],"bytes":[437,447]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:23"},"@entry":{"kind":"entry","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@entry"},"15:7":{"kind":"statement","span":{"start":[15,7],"end":[15,19],"bytes":[456,468]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@15:7"},"@exit":{"kind":"exit","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"14:7","kind":"fallthrough"},{"src":"14:7","dst":"@exit","kind":"exception"},{"src":"14:7","dst":"15:7","kind":"fallthrough"},{"src":"15:7","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"14:7"},{"src":"14:7","dst":"15:7"}],"ddg":[{"src":"@entry","dst":"14:7","var":"part","prov":["reaching-defs"]},{"src":"@entry","dst":"14:7","var":"this.parts.push","prov":["reaching-defs"]},{"src":"@entry","dst":"15:7","var":"this","prov":["reaching-defs"]}]},"build":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","kind":"method","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"name":"build","signature":"src/util.StringUtil.Builder.build","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"18:14":{"kind":"call","span":{"start":[18,14],"end":[18,34],"bytes":[510,530]},"callee":"can://slim/@external/(builtin)/join","method_name":"join","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["\"/\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:14"},"@entry":{"kind":"entry","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@entry"},"18:7":{"kind":"statement","span":{"start":[18,7],"end":[18,35],"bytes":[503,531]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:7"},"@exit":{"kind":"exit","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"18:7","kind":"fallthrough"},{"src":"18:7","dst":"@exit","kind":"exception"},{"src":"18:7","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"18:7"}],"ddg":[{"src":"@entry","dst":"18:7","var":"this.parts.join","prov":["reaching-defs"]}]},"constructor":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","kind":"constructor","span":{"start":[0,0],"end":[0,0],"bytes":[0,0]},"name":"constructor","signature":"src/util.StringUtil.Builder.constructor","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":true,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"parts":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/parts","kind":"field","span":{"start":[12,5],"end":[12,34],"bytes":[355,384]},"name":"parts","type":"string[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"repeat":{"id":"can://slim/typescript/src/util.ts/StringUtil/repeat","kind":"function","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"name":"repeat","signature":"src/util.StringUtil.repeat","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":26,"end_column":35,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0"},{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":37,"end_column":46,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"4:12":{"kind":"call","span":{"start":[4,12],"end":[4,29],"bytes":[204,221]},"callee":"can://slim/@external/(builtin)/repeat","method_name":"repeat","receiver_expr":"slug(s)","receiver_type":"string","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12"},"4:12/2":{"kind":"call","span":{"start":[4,12],"end":[4,19],"bytes":[204,211]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12/2"},"@entry":{"kind":"entry","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@entry"},"4:5":{"kind":"statement","span":{"start":[4,5],"end":[4,30],"bytes":[197,222]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5"},"@exit":{"kind":"exit","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"4:5","kind":"fallthrough"},{"src":"4:5","dst":"@exit","kind":"exception"},{"src":"4:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"4:5"}],"ddg":[{"src":"@entry","dst":"4:5","var":"n","prov":["reaching-defs"]},{"src":"@entry","dst":"4:5","var":"s","prov":["reaching-defs"]}]},"slug":{"id":"can://slim/typescript/src/util.ts/StringUtil/slug","kind":"function","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"name":"slug","signature":"src/util.StringUtil.slug","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"8:12":{"kind":"call","span":{"start":[8,12],"end":[8,48],"bytes":[283,319]},"callee":"can://slim/@external/(builtin)/replace","method_name":"replace","receiver_expr":"s.toLowerCase()","receiver_type":"string","argument_types":["RegExp","\"-\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12"},"8:12/2":{"kind":"call","span":{"start":[8,12],"end":[8,27],"bytes":[283,298]},"callee":"can://slim/@external/(builtin)/toLowerCase","method_name":"toLowerCase","receiver_expr":"s","receiver_type":"string","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12/2"},"@entry":{"kind":"entry","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@entry"},"8:5":{"kind":"statement","span":{"start":[8,5],"end":[8,49],"bytes":[276,320]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:5"},"@exit":{"kind":"exit","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:5","kind":"fallthrough"},{"src":"8:5","dst":"@exit","kind":"exception"},{"src":"8:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:5"}],"ddg":[{"src":"@entry","dst":"8:5","var":"s.toLowerCase","prov":["reaching-defs"]}]}},"fields":{},"is_exported":true,"is_ambient":false}},"functions":{"classify":{"id":"can://slim/typescript/src/util.ts/classify","kind":"function","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"name":"classify","signature":"src/util.classify","comments":[{"content":"Generic top-level function with a nested helper, to exercise inner_callables + generics.","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"decorators":[],"parameters":[{"name":"items","type":"T[]","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":54,"end_column":64,"id":"can://slim/typescript/src/util.ts/classify@formal_in:0"}],"type_parameters":[{"name":"T","constraint":"{ name: string }"}],"return_type":"Record","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"30:15":{"kind":"call","span":{"start":[30,15],"end":[30,26],"bytes":[884,895]},"callee":"can://slim/typescript/src/util.ts/classify/keyOf","method_name":"keyOf","argument_types":["T"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@30:15"},"31:5":{"kind":"call","span":{"start":[31,5],"end":[31,31],"bytes":[901,927]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"(out[k] ??= [])","receiver_type":"T[]","argument_types":["T"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@31:5"},"@entry":{"kind":"entry","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"id":"can://slim/typescript/src/util.ts/classify@entry"},"25:3":{"kind":"statement","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify@25:3"},"28:3":{"kind":"statement","span":{"start":[28,3],"end":[28,39],"bytes":[803,839]},"id":"can://slim/typescript/src/util.ts/classify@28:3"},"29:3":{"kind":"statement","span":{"start":[29,3],"end":[32,4],"bytes":[842,932]},"id":"can://slim/typescript/src/util.ts/classify@29:3"},"30:5":{"kind":"statement","span":{"start":[30,5],"end":[30,27],"bytes":[874,896]},"id":"can://slim/typescript/src/util.ts/classify@30:5"},"33:3":{"kind":"statement","span":{"start":[33,3],"end":[33,14],"bytes":[935,946]},"id":"can://slim/typescript/src/util.ts/classify@33:3"},"@exit":{"kind":"exit","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"id":"can://slim/typescript/src/util.ts/classify@exit"}},"callables":{"keyOf":{"id":"can://slim/typescript/src/util.ts/classify/keyOf","kind":"function","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"name":"keyOf","signature":"src/util.classify.keyOf","comments":[],"decorators":[],"parameters":[{"name":"item","type":"T","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":25,"end_line":25,"start_column":18,"end_column":25,"id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,31],"bytes":[776,795]},"callee":"can://slim/@external/(builtin)/charAt","method_name":"charAt","receiver_expr":"item.name","receiver_type":"string","argument_types":["0"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:12"},"@entry":{"kind":"entry","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@entry"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,32],"bytes":[769,796]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:5"},"@exit":{"kind":"exit","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@exit"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"26:5"}],"ddg":[{"src":"@entry","dst":"26:5","var":"item.name.charAt","prov":["reaching-defs"]}]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"25:3","kind":"fallthrough"},{"src":"25:3","dst":"@exit","kind":"exception"},{"src":"25:3","dst":"28:3","kind":"fallthrough"},{"src":"28:3","dst":"29:3","kind":"fallthrough"},{"src":"29:3","dst":"30:5","kind":"true"},{"src":"29:3","dst":"33:3","kind":"false"},{"src":"30:5","dst":"@exit","kind":"exception"},{"src":"30:5","dst":"31:5","kind":"fallthrough"},{"src":"31:5","dst":"@exit","kind":"exception"},{"src":"31:5","dst":"29:3","kind":"loop_back"},{"src":"33:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"25:3"},{"src":"25:3","dst":"28:3"},{"src":"25:3","dst":"29:3"},{"src":"29:3","dst":"30:5"},{"src":"29:3","dst":"33:3"},{"src":"30:5","dst":"31:5"},{"src":"31:5","dst":"29:3"}],"ddg":[{"src":"@entry","dst":"29:3","var":"items","prov":["reaching-defs"]},{"src":"28:3","dst":"31:5","var":"out[*]","prov":["reaching-defs"]},{"src":"28:3","dst":"33:3","var":"out","prov":["reaching-defs"]},{"src":"29:3","dst":"30:5","var":"item","prov":["reaching-defs"]},{"src":"29:3","dst":"31:5","var":"item","prov":["reaching-defs"]},{"src":"30:5","dst":"31:5","var":"k","prov":["reaching-defs"]},{"src":"31:5","dst":"31:5","var":"out[*]","prov":["reaching-defs"]},{"src":"31:5","dst":"33:3","var":"out","prov":["reaching-defs"]}]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"54886cff7e11ccadc987571f508b2aef2f324b14e63d8ad52100499851d130fa"}},"call_graph":[{"src":"can://slim/typescript/src/controllers.ts","dst":"can://slim/typescript/src/controllers.ts/Controller","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/index.ts","dst":"can://slim/typescript/src/index.ts/main","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Param","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/services.ts/UserService/describeAll","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/createGuest","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/list","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/show","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/announce","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/Robot/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/@external/(builtin)/log","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/models.ts/User/constructor","dst":"can://slim/typescript/src/models.ts/Entity/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Named/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Robot/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/services.ts/nextId","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/makeGuestName","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/@external/(builtin)/map","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll/","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/loginAll","dst":"can://slim/typescript/src/models.ts/User/recordLogin","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/typescript/src/util.ts/classify/keyOf","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify/keyOf","dst":"can://slim/@external/(builtin)/charAt","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/@external/(builtin)/repeat","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/replace","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/toLowerCase","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","dst":"can://slim/@external/(builtin)/join","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/typescript/src/services.ts/UserService/describeAll/","prov":["defuse"],"weight":1}],"param_in":[],"param_out":[],"artifacts":{"package.json":{"id":"can://slim/artifact/package.json","kind":"artifact","path":"package.json","format":"json","roles":["dependency-manifest","tool-config"],"size_bytes":88,"sha256":"277f174033b3f17dcd3ba9a550b53289624f034606303cef18a3f84ab7156c67","source":"{\n \"name\": \"sample-app\",\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"private\": true\n}\n","extraction":"none","config_keys":[]},"tsconfig.json":{"id":"can://slim/artifact/tsconfig.json","kind":"artifact","path":"tsconfig.json","format":"json","roles":["tool-config"],"size_bytes":289,"sha256":"72f24fc616456ab556dd8e7c886264214cb344547b32b972eb476467af0a9cab","source":"{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"experimentalDecorators\": true,\n \"emitDecoratorMetadata\": true\n },\n \"include\": [\"src/**/*.ts\"]\n}\n","extraction":"full","config_keys":[{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.target","key":"compilerOptions.target","namespace":"json","value":"ES2022","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.module","key":"compilerOptions.module","namespace":"json","value":"ESNext","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.moduleResolution","key":"compilerOptions.moduleResolution","namespace":"json","value":"bundler","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.strict","key":"compilerOptions.strict","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.esModuleInterop","key":"compilerOptions.esModuleInterop","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.skipLibCheck","key":"compilerOptions.skipLibCheck","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.experimentalDecorators","key":"compilerOptions.experimentalDecorators","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.emitDecoratorMetadata","key":"compilerOptions.emitDecoratorMetadata","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/include.0","key":"include.0","namespace":"json","value":"src/**/*.ts","references":[]}]}},"dependencies":[],"unresolved_imports":[],"config_uses":[],"config_reads":[],"entrypoint_report":{"frameworks_detected":[],"rulesets":["shipped"],"unresolved":{"Get":2,"Controller":1},"errors":[]},"external_symbols":{"can://slim/@external/(builtin)/log":{"id":"can://slim/@external/(builtin)/log","kind":"external","module":"(builtin)","name":"log"},"can://slim/@external/(builtin)/push":{"id":"can://slim/@external/(builtin)/push","kind":"external","module":"(builtin)","name":"push"},"can://slim/@external/(builtin)/map":{"id":"can://slim/@external/(builtin)/map","kind":"external","module":"(builtin)","name":"map"},"can://slim/@external/(builtin)/charAt":{"id":"can://slim/@external/(builtin)/charAt","kind":"external","module":"(builtin)","name":"charAt"},"can://slim/@external/(builtin)/repeat":{"id":"can://slim/@external/(builtin)/repeat","kind":"external","module":"(builtin)","name":"repeat"},"can://slim/@external/(builtin)/replace":{"id":"can://slim/@external/(builtin)/replace","kind":"external","module":"(builtin)","name":"replace"},"can://slim/@external/(builtin)/toLowerCase":{"id":"can://slim/@external/(builtin)/toLowerCase","kind":"external","module":"(builtin)","name":"toLowerCase"},"can://slim/@external/(builtin)/join":{"id":"can://slim/@external/(builtin)/join","kind":"external","module":"(builtin)","name":"join"}},"synthesized_callables":{"can://slim/typescript/src/controllers.ts/Controller@5:10":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Get@8:10":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Param@11:10":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"callable"},"can://slim/typescript/src/services.ts/UserService/describeAll@37:27":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"callable"}}}} \ No newline at end of file diff --git a/tests/resources/typescript/analysis_json/v2/a4/analysis.json b/tests/resources/typescript/analysis_json/v2/a4/analysis.json index ceeebe11..756f851c 100644 --- a/tests/resources/typescript/analysis_json/v2/a4/analysis.json +++ b/tests/resources/typescript/analysis_json/v2/a4/analysis.json @@ -1 +1 @@ -{"schema_version":"2.0.0","language":"typescript","max_level":4,"k_limit":3,"analyzer":{"name":"codeanalyzer-typescript","version":"1.5.3"},"application":{"id":"can://slim","kind":"application","symbol_table":{"src/controllers.ts":{"id":"can://slim/typescript/src/controllers.ts","kind":"module","span":{"start":[1,1],"end":[29,1],"bytes":[0,699]},"source":"import { UserService } from \"./services\";\n\n// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.\nfunction Controller(prefix: string): ClassDecorator {\n return () => undefined;\n}\nfunction Get(path: string): MethodDecorator {\n return () => undefined;\n}\nfunction Param(name: string): ParameterDecorator {\n return () => undefined;\n}\n\n@Controller(\"/users\")\nexport class UserController {\n constructor(private readonly service: UserService) {}\n\n @Get(\"/:id\")\n show(@Param(\"id\") id: string): string {\n const user = this.service.create(id);\n return user.describe();\n }\n\n @Get(\"/\")\n list(): string[] {\n return this.service.describeAll();\n }\n}\n","imports":[{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":42,"resolved_module":"src/services.ts"}],"exports":[],"comments":[{"content":"// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.","is_docstring":false,"start_line":3,"end_line":3,"start_column":1,"end_column":101}],"types":{"UserController":{"id":"can://slim/typescript/src/controllers.ts/UserController","kind":"class","span":{"start":[14,1],"end":[28,2],"bytes":[380,698]},"name":"UserController","signature":"src/controllers.UserController","comments":[],"decorators":[{"name":"Controller","positional_arguments":["\"/users\""],"keyword_arguments":{},"start_line":14,"end_line":14,"start_column":1,"end_column":22}],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"show":{"id":"can://slim/typescript/src/controllers.ts/UserController/show","kind":"method","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"name":"show","signature":"src/controllers.UserController.show","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/:id\""],"keyword_arguments":{},"start_line":18,"end_line":18,"start_column":3,"end_column":15}],"parameters":[{"name":"id","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[{"name":"Param","positional_arguments":["\"id\""],"keyword_arguments":{},"start_line":19,"end_line":19,"start_column":8,"end_column":20}],"start_line":19,"end_line":19,"start_column":8,"end_column":31,"id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"20:18":{"kind":"call","span":{"start":[20,18],"end":[20,41],"bytes":[563,586]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this.service","receiver_type":"UserService","argument_types":["string"],"type_arguments":[],"return_type":"import(\"./models\").User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:18"},"21:12":{"kind":"call","span":{"start":[21,12],"end":[21,27],"bytes":[599,614]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"user","receiver_type":"import(\"./models\").User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:12"},"19:9":{"kind":"call","span":{"start":[19,9],"end":[19,20],"bytes":[512,523]},"callee":"can://slim/typescript/src/controllers.ts/Param","method_name":"Param","argument_types":["\"id\""],"type_arguments":[],"return_type":"ParameterDecorator","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@19:9"},"@entry":{"kind":"entry","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@entry"},"20:5":{"kind":"statement","span":{"start":[20,5],"end":[20,42],"bytes":[550,587]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:5"},"21:5":{"kind":"statement","span":{"start":[21,5],"end":[21,28],"bytes":[592,615]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:5"},"@exit":{"kind":"exit","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@exit"},"@formal_in:0":{"kind":"formal_in","of":"id","id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_out"},"20:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"20:5","id":"can://slim/typescript/src/controllers.ts/UserController/show@20:5/actual_in:0"},"20:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"20:5","id":"can://slim/typescript/src/controllers.ts/UserController/show@20:5/actual_out"},"21:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"21:5","id":"can://slim/typescript/src/controllers.ts/UserController/show@21:5/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"20:5","kind":"fallthrough"},{"src":"20:5","dst":"@exit","kind":"exception"},{"src":"20:5","dst":"21:5","kind":"fallthrough"},{"src":"21:5","dst":"@exit","kind":"exception"},{"src":"21:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"20:5"},{"src":"20:5","dst":"21:5"}],"ddg":[{"src":"@entry","dst":"20:5","var":"id","prov":["reaching-defs"]},{"src":"@entry","dst":"20:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"20:5","var":"this.service.create","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"20:5","var":"id","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"20:5/actual_in:0","var":"id","prov":["reaching-defs"]},{"src":"20:5","dst":"21:5","var":"user.describe","prov":["reaching-defs"]},{"src":"20:5/actual_out","dst":"20:5","var":"$ret","prov":["reaching-defs"]},{"src":"21:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]},{"src":"21:5/actual_out","dst":"21:5","var":"$ret","prov":["reaching-defs"]}],"summary":[{"src":"20:5","dst":"20:5","var":"src/services.nextId"},{"src":"20:5/actual_in:0","dst":"20:5/actual_out"}]},"list":{"id":"can://slim/typescript/src/controllers.ts/UserController/list","kind":"method","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"name":"list","signature":"src/controllers.UserController.list","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/\""],"keyword_arguments":{},"start_line":24,"end_line":24,"start_column":3,"end_column":12}],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,38],"bytes":[665,691]},"callee":"can://slim/typescript/src/services.ts/UserService/describeAll","method_name":"describeAll","receiver_expr":"this.service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:12"},"@entry":{"kind":"entry","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@entry"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,39],"bytes":[658,692]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:5"},"@exit":{"kind":"exit","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/UserController/list@formal_out"},"26:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"26:5","id":"can://slim/typescript/src/controllers.ts/UserController/list@26:5/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"26:5"}],"ddg":[{"src":"@entry","dst":"26:5","var":"this.service.describeAll","prov":["reaching-defs"]},{"src":"26:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]},{"src":"26:5/actual_out","dst":"26:5","var":"$ret","prov":["reaching-defs"]}],"summary":[]},"constructor":{"id":"can://slim/typescript/src/controllers.ts/UserController/constructor","kind":"constructor","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"name":"constructor","signature":"src/controllers.UserController.constructor","comments":[],"decorators":[],"parameters":[{"name":"service","type":"UserService","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":16,"end_line":16,"start_column":15,"end_column":52,"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@exit"},"@formal_in:0":{"kind":"formal_in","of":"service","id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[],"summary":[]}},"fields":{"service":{"id":"can://slim/typescript/src/controllers.ts/UserController/service","kind":"field","name":"service","type":"UserService","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"Controller":{"id":"can://slim/typescript/src/controllers.ts/Controller","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"name":"Controller","signature":"src/controllers.Controller","comments":[],"decorators":[],"parameters":[{"name":"prefix","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":21,"end_column":35,"id":"can://slim/typescript/src/controllers.ts/Controller@formal_in:0"}],"type_parameters":[],"return_type":"ClassDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"id":"can://slim/typescript/src/controllers.ts/Controller@entry"},"5:3":{"kind":"statement","span":{"start":[5,3],"end":[5,26],"bytes":[200,223]},"id":"can://slim/typescript/src/controllers.ts/Controller@5:3"},"@exit":{"kind":"exit","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"id":"can://slim/typescript/src/controllers.ts/Controller@exit"},"@formal_in:0":{"kind":"formal_in","of":"prefix","id":"can://slim/typescript/src/controllers.ts/Controller@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Controller@formal_out"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"arrow","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"name":"(anonymous)","signature":"src/controllers.Controller.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@entry"},"5:16":{"kind":"statement","span":{"start":[5,16],"end":[5,25],"bytes":[213,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@5:16"},"@exit":{"kind":"exit","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Controller/@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:16","kind":"fallthrough"},{"src":"5:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:16"}],"ddg":[{"src":"5:16","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:3","kind":"fallthrough"},{"src":"5:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:3"}],"ddg":[{"src":"5:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"Get":{"id":"can://slim/typescript/src/controllers.ts/Get","kind":"function","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"name":"Get","signature":"src/controllers.Get","comments":[],"decorators":[],"parameters":[{"name":"path","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":14,"end_column":26,"id":"can://slim/typescript/src/controllers.ts/Get@formal_in:0"}],"type_parameters":[],"return_type":"MethodDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"id":"can://slim/typescript/src/controllers.ts/Get@entry"},"8:3":{"kind":"statement","span":{"start":[8,3],"end":[8,26],"bytes":[274,297]},"id":"can://slim/typescript/src/controllers.ts/Get@8:3"},"@exit":{"kind":"exit","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"id":"can://slim/typescript/src/controllers.ts/Get@exit"},"@formal_in:0":{"kind":"formal_in","of":"path","id":"can://slim/typescript/src/controllers.ts/Get@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Get@formal_out"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"arrow","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"name":"(anonymous)","signature":"src/controllers.Get.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@entry"},"8:16":{"kind":"statement","span":{"start":[8,16],"end":[8,25],"bytes":[287,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@8:16"},"@exit":{"kind":"exit","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Get/@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:16","kind":"fallthrough"},{"src":"8:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:16"}],"ddg":[{"src":"8:16","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:3","kind":"fallthrough"},{"src":"8:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:3"}],"ddg":[{"src":"8:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"Param":{"id":"can://slim/typescript/src/controllers.ts/Param","kind":"function","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"name":"Param","signature":"src/controllers.Param","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":10,"end_line":10,"start_column":16,"end_column":28,"id":"can://slim/typescript/src/controllers.ts/Param@formal_in:0"}],"type_parameters":[],"return_type":"ParameterDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"id":"can://slim/typescript/src/controllers.ts/Param@entry"},"11:3":{"kind":"statement","span":{"start":[11,3],"end":[11,26],"bytes":[353,376]},"id":"can://slim/typescript/src/controllers.ts/Param@11:3"},"@exit":{"kind":"exit","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"id":"can://slim/typescript/src/controllers.ts/Param@exit"},"@formal_in:0":{"kind":"formal_in","of":"name","id":"can://slim/typescript/src/controllers.ts/Param@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Param@formal_out"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"arrow","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"name":"(anonymous)","signature":"src/controllers.Param.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@entry"},"11:16":{"kind":"statement","span":{"start":[11,16],"end":[11,25],"bytes":[366,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@11:16"},"@exit":{"kind":"exit","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Param/@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"11:16","kind":"fallthrough"},{"src":"11:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"11:16"}],"ddg":[{"src":"11:16","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"11:3","kind":"fallthrough"},{"src":"11:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"11:3"}],"ddg":[{"src":"11:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d42b8f615d51575e3436409b9fce70862182b6071da40471b4be9b95f7c9ee4c"},"src/index.ts":{"id":"can://slim/typescript/src/index.ts","kind":"module","span":{"start":[1,1],"end":[26,1],"bytes":[0,742]},"source":"import { UserController } from \"./controllers\";\nimport { Robot, Role, User } from \"./models\";\nimport { UserService, announce } from \"./services\";\nimport { StringUtil } from \"./util\";\n\nexport function main(): void {\n const service = new UserService(100);\n service.create(\"Ada\", Role.Admin);\n service.createGuest();\n\n const controller = new UserController(service);\n controller.list();\n controller.show(\"42\");\n\n // interface-typed dispatch — RTA should expand announce -> {User,Robot}.describe\n announce(new User(1, \"Ada\", Role.Admin));\n announce(new Robot(\"r2d2\"));\n\n const slug = StringUtil.repeat(\"hello world\", 2);\n const builder = new StringUtil.Builder();\n builder.add(\"a\").add(\"b\").build();\n console.log(slug);\n}\n\nmain();\n","imports":[{"module":"./controllers","name":"UserController","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":48,"resolved_module":"src/controllers.ts"},{"module":"./models","name":"Robot","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./services","name":"announce","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./util","name":"StringUtil","is_type_only":false,"import_kind":"named","start_line":4,"end_line":4,"start_column":1,"end_column":37,"resolved_module":"src/util.ts"}],"exports":[],"comments":[],"types":{},"functions":{"main":{"id":"can://slim/typescript/src/index.ts/main","kind":"function","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"name":"main","signature":"src/index.main","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"void","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"7:19":{"kind":"call","span":{"start":[7,19],"end":[7,39],"bytes":[233,253]},"callee":"can://slim/typescript/src/services.ts/UserService/constructor","method_name":"UserService","argument_types":["100"],"type_arguments":[],"return_type":"UserService","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@7:19"},"8:3":{"kind":"call","span":{"start":[8,3],"end":[8,36],"bytes":[257,290]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"service","receiver_type":"UserService","argument_types":["\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@8:3"},"9:3":{"kind":"call","span":{"start":[9,3],"end":[9,24],"bytes":[294,315]},"callee":"can://slim/typescript/src/services.ts/UserService/createGuest","method_name":"createGuest","receiver_expr":"service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@9:3"},"11:22":{"kind":"call","span":{"start":[11,22],"end":[11,49],"bytes":[339,366]},"callee":"can://slim/typescript/src/controllers.ts/UserController/constructor","method_name":"UserController","argument_types":["UserService"],"type_arguments":[],"return_type":"UserController","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@11:22"},"12:3":{"kind":"call","span":{"start":[12,3],"end":[12,20],"bytes":[370,387]},"callee":"can://slim/typescript/src/controllers.ts/UserController/list","method_name":"list","receiver_expr":"controller","receiver_type":"UserController","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@12:3"},"13:3":{"kind":"call","span":{"start":[13,3],"end":[13,24],"bytes":[391,412]},"callee":"can://slim/typescript/src/controllers.ts/UserController/show","method_name":"show","receiver_expr":"controller","receiver_type":"UserController","argument_types":["\"42\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@13:3"},"16:3":{"kind":"call","span":{"start":[16,3],"end":[16,43],"bytes":[503,543]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["User"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:3"},"16:12":{"kind":"call","span":{"start":[16,12],"end":[16,42],"bytes":[512,542]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["1","\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:12"},"17:3":{"kind":"call","span":{"start":[17,3],"end":[17,30],"bytes":[547,574]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["Robot"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:3"},"17:12":{"kind":"call","span":{"start":[17,12],"end":[17,29],"bytes":[556,573]},"callee":"can://slim/typescript/src/models.ts/Robot/constructor","method_name":"Robot","argument_types":["\"r2d2\""],"type_arguments":[],"return_type":"Robot","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:12"},"19:16":{"kind":"call","span":{"start":[19,16],"end":[19,51],"bytes":[592,627]},"callee":"can://slim/typescript/src/util.ts/StringUtil/repeat","method_name":"repeat","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":["\"hello world\"","2"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@19:16"},"20:19":{"kind":"call","span":{"start":[20,19],"end":[20,43],"bytes":[647,671]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","method_name":"Builder","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":[],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@20:19"},"21:3":{"kind":"call","span":{"start":[21,3],"end":[21,36],"bytes":[675,708]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","method_name":"build","receiver_expr":"builder.add(\"a\").add(\"b\")","receiver_type":"StringUtil.Builder","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3"},"21:3/2":{"kind":"call","span":{"start":[21,3],"end":[21,28],"bytes":[675,700]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder.add(\"a\")","receiver_type":"StringUtil.Builder","argument_types":["\"b\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/2"},"21:3/3":{"kind":"call","span":{"start":[21,3],"end":[21,19],"bytes":[675,691]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder","receiver_type":"StringUtil.Builder","argument_types":["\"a\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/3"},"22:3":{"kind":"call","span":{"start":[22,3],"end":[22,20],"bytes":[712,729]},"callee":"can://slim/@external/(builtin)/log","method_name":"log","receiver_expr":"console","receiver_type":"Console","argument_types":["string"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@22:3"},"@entry":{"kind":"entry","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"id":"can://slim/typescript/src/index.ts/main@entry"},"7:3":{"kind":"statement","span":{"start":[7,3],"end":[7,40],"bytes":[217,254]},"id":"can://slim/typescript/src/index.ts/main@7:3"},"11:3":{"kind":"statement","span":{"start":[11,3],"end":[11,50],"bytes":[320,367]},"id":"can://slim/typescript/src/index.ts/main@11:3"},"19:3":{"kind":"statement","span":{"start":[19,3],"end":[19,52],"bytes":[579,628]},"id":"can://slim/typescript/src/index.ts/main@19:3"},"20:3":{"kind":"statement","span":{"start":[20,3],"end":[20,44],"bytes":[631,672]},"id":"can://slim/typescript/src/index.ts/main@20:3"},"@exit":{"kind":"exit","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"id":"can://slim/typescript/src/index.ts/main@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/index.ts/main@formal_out"},"11:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"11:3","id":"can://slim/typescript/src/index.ts/main@11:3/actual_out"},"12:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"12:3","id":"can://slim/typescript/src/index.ts/main@12:3/actual_out"},"13:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"13:3","id":"can://slim/typescript/src/index.ts/main@13:3/actual_out"},"7:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"7:3","id":"can://slim/typescript/src/index.ts/main@7:3/actual_in:0"},"8:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"8:3","id":"can://slim/typescript/src/index.ts/main@8:3/actual_in:0"},"8:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"8:3","id":"can://slim/typescript/src/index.ts/main@8:3/actual_out"},"8:3/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"8:3","id":"can://slim/typescript/src/index.ts/main@8:3/actual_in:1"},"11:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"11:3","id":"can://slim/typescript/src/index.ts/main@11:3/actual_in:0"},"13:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"13:3","id":"can://slim/typescript/src/index.ts/main@13:3/actual_in:0"},"16:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"16:3","id":"can://slim/typescript/src/index.ts/main@16:3/actual_in:0"},"16:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"16:3","id":"can://slim/typescript/src/index.ts/main@16:3/actual_out"},"16:3/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"16:3","id":"can://slim/typescript/src/index.ts/main@16:3/actual_in:1"},"16:3/actual_in:2":{"kind":"actual_in","of":"arg2","parent":"16:3","id":"can://slim/typescript/src/index.ts/main@16:3/actual_in:2"},"17:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"17:3","id":"can://slim/typescript/src/index.ts/main@17:3/actual_in:0"},"17:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"17:3","id":"can://slim/typescript/src/index.ts/main@17:3/actual_out"},"19:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"19:3","id":"can://slim/typescript/src/index.ts/main@19:3/actual_in:0"},"19:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"19:3","id":"can://slim/typescript/src/index.ts/main@19:3/actual_out"},"19:3/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"19:3","id":"can://slim/typescript/src/index.ts/main@19:3/actual_in:1"},"21:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"21:3","id":"can://slim/typescript/src/index.ts/main@21:3/actual_in:0"},"22:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"22:3","id":"can://slim/typescript/src/index.ts/main@22:3/actual_in:0"},"22:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"22:3","id":"can://slim/typescript/src/index.ts/main@22:3/actual_out"},"7:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"7:3","id":"can://slim/typescript/src/index.ts/main@7:3/actual_out"},"9:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"9:3","id":"can://slim/typescript/src/index.ts/main@9:3/actual_out"},"21:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"21:3","id":"can://slim/typescript/src/index.ts/main@21:3/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"7:3","kind":"fallthrough"},{"src":"11:3","dst":"@exit","kind":"exception"},{"src":"11:3","dst":"12:3","kind":"fallthrough"},{"src":"12:3","dst":"@exit","kind":"exception"},{"src":"12:3","dst":"13:3","kind":"fallthrough"},{"src":"13:3","dst":"@exit","kind":"exception"},{"src":"13:3","dst":"16:3","kind":"fallthrough"},{"src":"16:3","dst":"@exit","kind":"exception"},{"src":"16:3","dst":"17:3","kind":"fallthrough"},{"src":"17:3","dst":"@exit","kind":"exception"},{"src":"17:3","dst":"19:3","kind":"fallthrough"},{"src":"19:3","dst":"@exit","kind":"exception"},{"src":"19:3","dst":"20:3","kind":"fallthrough"},{"src":"20:3","dst":"@exit","kind":"exception"},{"src":"20:3","dst":"21:3","kind":"fallthrough"},{"src":"21:3","dst":"@exit","kind":"exception"},{"src":"21:3","dst":"22:3","kind":"fallthrough"},{"src":"22:3","dst":"@exit","kind":"exception"},{"src":"22:3","dst":"@exit","kind":"fallthrough"},{"src":"7:3","dst":"@exit","kind":"exception"},{"src":"7:3","dst":"8:3","kind":"fallthrough"},{"src":"8:3","dst":"@exit","kind":"exception"},{"src":"8:3","dst":"9:3","kind":"fallthrough"},{"src":"9:3","dst":"@exit","kind":"exception"},{"src":"9:3","dst":"11:3","kind":"fallthrough"}],"cdg":[{"src":"@entry","dst":"7:3"},{"src":"11:3","dst":"12:3"},{"src":"12:3","dst":"13:3"},{"src":"13:3","dst":"16:3"},{"src":"16:3","dst":"17:3"},{"src":"17:3","dst":"19:3"},{"src":"19:3","dst":"20:3"},{"src":"20:3","dst":"21:3"},{"src":"21:3","dst":"22:3"},{"src":"7:3","dst":"8:3"},{"src":"8:3","dst":"9:3"},{"src":"9:3","dst":"11:3"}],"ddg":[{"src":"@entry","dst":"13:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"8:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"9:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"11:3","dst":"12:3","var":"controller.list","prov":["reaching-defs"]},{"src":"11:3","dst":"13:3","var":"controller.show","prov":["reaching-defs"]},{"src":"11:3/actual_out","dst":"11:3","var":"$ret","prov":["reaching-defs"]},{"src":"12:3/actual_out","dst":"12:3","var":"$ret","prov":["reaching-defs"]},{"src":"13:3/actual_out","dst":"13:3","var":"$ret","prov":["reaching-defs"]},{"src":"16:3/actual_out","dst":"16:3","var":"$ret","prov":["reaching-defs"]},{"src":"17:3/actual_out","dst":"17:3","var":"$ret","prov":["reaching-defs"]},{"src":"19:3","dst":"22:3","var":"slug","prov":["reaching-defs"]},{"src":"19:3/actual_out","dst":"19:3","var":"$ret","prov":["reaching-defs"]},{"src":"20:3","dst":"21:3","var":"builder.add","prov":["reaching-defs"]},{"src":"21:3/actual_out","dst":"21:3","var":"$ret","prov":["reaching-defs"]},{"src":"7:3","dst":"11:3","var":"service","prov":["reaching-defs"]},{"src":"7:3","dst":"11:3/actual_in:0","var":"service","prov":["reaching-defs"]},{"src":"7:3","dst":"8:3","var":"service.create","prov":["reaching-defs"]},{"src":"7:3","dst":"9:3","var":"service.createGuest","prov":["reaching-defs"]},{"src":"7:3/actual_out","dst":"7:3","var":"$ret","prov":["reaching-defs"]},{"src":"8:3/actual_out","dst":"8:3","var":"$ret","prov":["reaching-defs"]},{"src":"9:3/actual_out","dst":"9:3","var":"$ret","prov":["reaching-defs"]}],"summary":[{"src":"13:3","dst":"13:3","var":"src/services.nextId"},{"src":"13:3/actual_in:0","dst":"13:3/actual_out"},{"src":"16:3/actual_in:0","dst":"16:3/actual_out"},{"src":"17:3/actual_in:0","dst":"17:3/actual_out"},{"src":"19:3/actual_in:0","dst":"19:3/actual_out"},{"src":"19:3/actual_in:1","dst":"19:3/actual_out"},{"src":"22:3/actual_in:0","dst":"22:3/actual_out"},{"src":"8:3","dst":"8:3","var":"src/services.nextId"},{"src":"8:3/actual_in:0","dst":"8:3/actual_out"},{"src":"8:3/actual_in:1","dst":"8:3/actual_out"},{"src":"9:3","dst":"9:3","var":"src/services.nextId"}]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"6de6f6ff5a01a5c7c750a93d5e10bae7b15817f386421f45c7527cfb7259d9b3"},"src/models.ts":{"id":"can://slim/typescript/src/models.ts","kind":"module","span":{"start":[1,1],"end":[65,1],"bytes":[0,1237]},"source":"/** Domain models for the sample app. */\n\nexport interface Identifiable {\n readonly id: T;\n}\n\nexport interface Named {\n name: string;\n describe(): string;\n}\n\nexport type UserId = string | number;\n\nexport enum Role {\n Admin = \"admin\",\n Member = \"member\",\n Guest = \"guest\",\n}\n\nexport const enum Flag {\n None = 0,\n Active = 1,\n}\n\n/** A user of the system. */\nexport abstract class Entity implements Identifiable {\n constructor(public readonly id: ID) {}\n abstract describe(): string;\n}\n\nexport class User extends Entity implements Named {\n private loginCount = 0;\n static instances = 0;\n\n constructor(\n id: UserId,\n public name: string,\n private role: Role = Role.Member,\n ) {\n super(id);\n User.instances++;\n }\n\n get isAdmin(): boolean {\n return this.role === Role.Admin;\n }\n\n describe(): string {\n return `${this.name} (${this.role})`;\n }\n\n async recordLogin(): Promise {\n this.loginCount += 1;\n return this.loginCount;\n }\n}\n\n/** A second, unrelated implementer of Named — drives RTA subtype expansion. */\nexport class Robot implements Named {\n constructor(public name: string) {}\n describe(): string {\n return `robot:${this.name}`;\n }\n}\n","imports":[],"exports":[],"comments":[{"content":"/** Domain models for the sample app. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41},{"content":"/** A user of the system. */","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29},{"content":"/** A second, unrelated implementer of Named — drives RTA subtype expansion. */","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"types":{"Entity":{"id":"can://slim/typescript/src/models.ts/Entity","kind":"class","span":{"start":[26,1],"end":[29,2],"bytes":[376,521]},"name":"Entity","signature":"src/models.Entity","comments":[{"content":"A user of the system.","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29}],"decorators":[],"base_classes":["src/models.Identifiable"],"implements_types":["src/models.Identifiable"],"type_parameters":[{"name":"ID","default":"string"}],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Entity/describe","kind":"method","span":{"start":[28,3],"end":[28,31],"bytes":[491,519]},"name":"describe","signature":"src/models.Entity.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":true,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[{"parameters":[],"return_type":"string","type_parameters":[],"start_line":28,"end_line":28}],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Entity/constructor","kind":"constructor","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"name":"constructor","signature":"src/models.Entity.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"ID","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"public","decorators":[],"start_line":27,"end_line":27,"start_column":15,"end_column":37,"id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"id":"can://slim/typescript/src/models.ts/Entity/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"id":"can://slim/typescript/src/models.ts/Entity/constructor@exit"},"@formal_in:0":{"kind":"formal_in","of":"id","id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[],"summary":[]}},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Entity/id","kind":"field","name":"id","type":"ID","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":true,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Identifiable"],"entrypoints":[],"is_entrypoint":false},"User":{"id":"can://slim/typescript/src/models.ts/User","kind":"class","span":{"start":[31,1],"end":[56,2],"bytes":[523,1015]},"name":"User","signature":"src/models.User","comments":[],"decorators":[],"base_classes":["src/models.Entity","src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/User/describe","kind":"method","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"name":"describe","signature":"src/models.User.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"id":"can://slim/typescript/src/models.ts/User/describe@entry"},"49:5":{"kind":"statement","span":{"start":[49,5],"end":[49,42],"bytes":[872,909]},"id":"can://slim/typescript/src/models.ts/User/describe@49:5"},"@exit":{"kind":"exit","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"id":"can://slim/typescript/src/models.ts/User/describe@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/User/describe@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"49:5","kind":"fallthrough"},{"src":"49:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"49:5"}],"ddg":[{"src":"@entry","dst":"49:5","var":"this.name","prov":["reaching-defs"]},{"src":"@entry","dst":"49:5","var":"this.role","prov":["reaching-defs"]},{"src":"49:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"recordLogin":{"id":"can://slim/typescript/src/models.ts/User/recordLogin","kind":"method","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"name":"recordLogin","signature":"src/models.User.recordLogin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@entry"},"53:5":{"kind":"statement","span":{"start":[53,5],"end":[53,26],"bytes":[960,981]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@53:5"},"54:5":{"kind":"statement","span":{"start":[54,5],"end":[54,28],"bytes":[986,1009]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@54:5"},"@exit":{"kind":"exit","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/User/recordLogin@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"53:5","kind":"fallthrough"},{"src":"53:5","dst":"54:5","kind":"fallthrough"},{"src":"54:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"53:5"},{"src":"@entry","dst":"54:5"}],"ddg":[{"src":"@entry","dst":"53:5","var":"this.loginCount","prov":["reaching-defs"]},{"src":"@entry","dst":"54:5","var":"this.loginCount","prov":["reaching-defs"]},{"src":"53:5","dst":"54:5","var":"this.loginCount","prov":["reaching-defs"]},{"src":"54:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"constructor":{"id":"can://slim/typescript/src/models.ts/User/constructor","kind":"constructor","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"name":"constructor","signature":"src/models.User.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"UserId","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":36,"end_line":36,"start_column":5,"end_column":15,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0"},{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":37,"end_line":37,"start_column":5,"end_column":24,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"accessibility":"private","decorators":[],"start_line":38,"end_line":38,"start_column":5,"end_column":37,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"40:5":{"kind":"call","span":{"start":[40,5],"end":[40,14],"bytes":[738,747]},"callee":"can://slim/typescript/src/models.ts/Entity/constructor","method_name":"super","argument_types":["UserId"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/models.ts/User/constructor@40:5"},"@entry":{"kind":"entry","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"id":"can://slim/typescript/src/models.ts/User/constructor@entry"},"41:5":{"kind":"statement","span":{"start":[41,5],"end":[41,22],"bytes":[753,770]},"id":"can://slim/typescript/src/models.ts/User/constructor@41:5"},"@exit":{"kind":"exit","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"id":"can://slim/typescript/src/models.ts/User/constructor@exit"},"@formal_in:0":{"kind":"formal_in","of":"id","id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0"},"@formal_in:1":{"kind":"formal_in","of":"name","id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1"},"@formal_in:2":{"kind":"formal_in","of":"role","id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/User/constructor@formal_out"},"40:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"40:5","id":"can://slim/typescript/src/models.ts/User/constructor@40:5/actual_out"},"40:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"40:5","id":"can://slim/typescript/src/models.ts/User/constructor@40:5/actual_in:0"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"40:5","kind":"fallthrough"},{"src":"40:5","dst":"@exit","kind":"exception"},{"src":"40:5","dst":"41:5","kind":"fallthrough"},{"src":"41:5","dst":"@exit","kind":"fallthrough"}],"cdg":[{"src":"@entry","dst":"40:5"},{"src":"40:5","dst":"41:5"}],"ddg":[{"src":"@entry","dst":"40:5","var":"id","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"40:5","var":"id","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"40:5/actual_in:0","var":"id","prov":["reaching-defs"]},{"src":"40:5/actual_out","dst":"40:5","var":"$ret","prov":["reaching-defs"]}],"summary":[]},"isAdmin#get":{"id":"can://slim/typescript/src/models.ts/User/isAdmin","kind":"getter","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"name":"isAdmin","signature":"src/models.User.isAdmin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"boolean","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"accessor_kind":"getter","overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@entry"},"45:5":{"kind":"statement","span":{"start":[45,5],"end":[45,37],"bytes":[807,839]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@45:5"},"@exit":{"kind":"exit","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/User/isAdmin@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"45:5","kind":"fallthrough"},{"src":"45:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"45:5"}],"ddg":[{"src":"@entry","dst":"45:5","var":"this.role","prov":["reaching-defs"]},{"src":"45:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"fields":{"loginCount":{"id":"can://slim/typescript/src/models.ts/User/loginCount","kind":"field","span":{"start":[32,3],"end":[32,26],"bytes":[585,608]},"name":"loginCount","type":"number","comments":[],"decorators":[],"initializer":"0","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"instances":{"id":"can://slim/typescript/src/models.ts/User/instances","kind":"field","span":{"start":[33,3],"end":[33,24],"bytes":[611,632]},"name":"instances","type":"number","comments":[],"decorators":[],"initializer":"0","is_static":true,"is_readonly":false,"is_optional":false,"is_abstract":false},"name":{"id":"can://slim/typescript/src/models.ts/User/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"role":{"id":"can://slim/typescript/src/models.ts/User/role","kind":"field","name":"role","type":"Role","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":false,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"extends_ids":["can://slim/typescript/src/models.ts/Entity"],"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Robot":{"id":"can://slim/typescript/src/models.ts/Robot","kind":"class","span":{"start":[59,1],"end":[64,2],"bytes":[1099,1236]},"name":"Robot","signature":"src/models.Robot","comments":[{"content":"A second, unrelated implementer of Named — drives RTA subtype expansion.","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"decorators":[],"base_classes":["src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Robot/describe","kind":"method","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"name":"describe","signature":"src/models.Robot.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"id":"can://slim/typescript/src/models.ts/Robot/describe@entry"},"62:5":{"kind":"statement","span":{"start":[62,5],"end":[62,33],"bytes":[1202,1230]},"id":"can://slim/typescript/src/models.ts/Robot/describe@62:5"},"@exit":{"kind":"exit","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"id":"can://slim/typescript/src/models.ts/Robot/describe@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/Robot/describe@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"62:5","kind":"fallthrough"},{"src":"62:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"62:5"}],"ddg":[{"src":"@entry","dst":"62:5","var":"this.name","prov":["reaching-defs"]},{"src":"62:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"constructor":{"id":"can://slim/typescript/src/models.ts/Robot/constructor","kind":"constructor","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"name":"constructor","signature":"src/models.Robot.constructor","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":60,"end_line":60,"start_column":15,"end_column":34,"id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"id":"can://slim/typescript/src/models.ts/Robot/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"id":"can://slim/typescript/src/models.ts/Robot/constructor@exit"},"@formal_in:0":{"kind":"formal_in","of":"name","id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[],"summary":[]}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Robot/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Identifiable":{"id":"can://slim/typescript/src/models.ts/Identifiable","kind":"interface","span":{"start":[3,1],"end":[5,2],"bytes":[42,105]},"name":"Identifiable","signature":"src/models.Identifiable","comments":[{"content":"Domain models for the sample app.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41}],"base_classes":[],"type_parameters":[{"name":"T","default":"string"}],"callables":{},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Identifiable/id","kind":"field","span":{"start":[4,3],"end":[4,18],"bytes":[88,103]},"name":"id","type":"T","comments":[],"decorators":[],"is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Named":{"id":"can://slim/typescript/src/models.ts/Named","kind":"interface","span":{"start":[7,1],"end":[10,2],"bytes":[107,171]},"name":"Named","signature":"src/models.Named","comments":[],"base_classes":[],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Named/describe","kind":"method","span":{"start":[9,3],"end":[9,22],"bytes":[150,169]},"name":"describe","signature":"src/models.Named.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Named/name","kind":"field","span":{"start":[8,3],"end":[8,16],"bytes":[134,147]},"name":"name","type":"string","comments":[],"decorators":[],"is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Role":{"id":"can://slim/typescript/src/models.ts/Role","kind":"enum","span":{"start":[14,1],"end":[18,2],"bytes":[212,291]},"name":"Role","signature":"src/models.Role","comments":[],"fields":{"Admin":{"id":"can://slim/typescript/src/models.ts/Role/Admin","kind":"field","span":{"start":[15,3],"end":[15,18],"bytes":[233,248]},"name":"Admin","value":"admin"},"Member":{"id":"can://slim/typescript/src/models.ts/Role/Member","kind":"field","span":{"start":[16,3],"end":[16,20],"bytes":[252,269]},"name":"Member","value":"member"},"Guest":{"id":"can://slim/typescript/src/models.ts/Role/Guest","kind":"field","span":{"start":[17,3],"end":[17,18],"bytes":[273,288]},"name":"Guest","value":"guest"}},"is_const":false,"is_exported":true,"is_ambient":false},"Flag":{"id":"can://slim/typescript/src/models.ts/Flag","kind":"enum","span":{"start":[20,1],"end":[23,2],"bytes":[293,345]},"name":"Flag","signature":"src/models.Flag","comments":[],"fields":{"None":{"id":"can://slim/typescript/src/models.ts/Flag/None","kind":"field","span":{"start":[21,3],"end":[21,11],"bytes":[320,328]},"name":"None","value":"0"},"Active":{"id":"can://slim/typescript/src/models.ts/Flag/Active","kind":"field","span":{"start":[22,3],"end":[22,13],"bytes":[332,342]},"name":"Active","value":"1"}},"is_const":true,"is_exported":true,"is_ambient":false},"UserId":{"id":"can://slim/typescript/src/models.ts/UserId","kind":"type_alias","span":{"start":[12,1],"end":[12,38],"bytes":[173,210]},"name":"UserId","signature":"src/models.UserId","comments":[],"aliased_type":"string | number","type_parameters":[],"is_exported":true,"is_ambient":false}},"functions":{},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d39ff571ccfda4b7c46923586b6b94d0e818a51be966f1ba40305650fd0ffc91"},"src/services.ts":{"id":"can://slim/typescript/src/services.ts","kind":"module","span":{"start":[1,1],"end":[48,1],"bytes":[0,1240]},"source":"import { type Named, Role, User, type UserId } from \"./models\";\n\n/** Pure helper — top-level function. */\nexport function makeGuestName(seed: number): string {\n return `guest-${seed}`;\n}\n\n/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */\nexport function announce(thing: Named): string {\n return thing.describe();\n}\n\n/** Arrow function bound to a const (function_expression-style callable). */\nexport const nextId = (n: number): UserId => n + 1;\n\nexport class UserService {\n private users: User[] = [];\n\n constructor(private readonly startId: number = 0) {}\n\n create(name: string, role: Role = Role.Member): User {\n const id = nextId(this.users.length + this.startId);\n const user = new User(id, name, role);\n this.users.push(user);\n return user;\n }\n\n createGuest(): User {\n const name = makeGuestName(this.users.length);\n return this.create(name, Role.Guest);\n }\n\n describeAll(): string[] {\n return this.users.map((u) => u.describe());\n }\n\n async loginAll(): Promise {\n let total = 0;\n for (const u of this.users) {\n total += await u.recordLogin();\n }\n return total;\n }\n}\n","imports":[{"module":"./models","name":"Named","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"UserId","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"}],"exports":[],"comments":[{"content":"/** Pure helper — top-level function. */","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41},{"content":"/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4},{"content":"/** Arrow function bound to a const (function_expression-style callable). */","is_docstring":true,"start_line":16,"end_line":16,"start_column":1,"end_column":77}],"types":{"UserService":{"id":"can://slim/typescript/src/services.ts/UserService","kind":"class","span":{"start":[19,1],"end":[47,2],"bytes":[558,1239]},"name":"UserService","signature":"src/services.UserService","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"create":{"id":"can://slim/typescript/src/services.ts/UserService/create","kind":"method","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"name":"create","signature":"src/services.UserService.create","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":10,"end_column":22,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":24,"end_column":48,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1"}],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"25:16":{"kind":"call","span":{"start":[25,16],"end":[25,56],"bytes":[744,784]},"callee":"can://slim/typescript/src/services.ts/nextId","method_name":"nextId","argument_types":["number"],"type_arguments":[],"return_type":"UserId","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@25:16"},"26:18":{"kind":"call","span":{"start":[26,18],"end":[26,42],"bytes":[803,827]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["UserId","string","Role"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@26:18"},"27:5":{"kind":"call","span":{"start":[27,5],"end":[27,26],"bytes":[833,854]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["User"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@27:5"},"@entry":{"kind":"entry","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"id":"can://slim/typescript/src/services.ts/UserService/create@entry"},"25:5":{"kind":"statement","span":{"start":[25,5],"end":[25,57],"bytes":[733,785]},"id":"can://slim/typescript/src/services.ts/UserService/create@25:5"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,43],"bytes":[790,828]},"id":"can://slim/typescript/src/services.ts/UserService/create@26:5"},"28:5":{"kind":"statement","span":{"start":[28,5],"end":[28,17],"bytes":[860,872]},"id":"can://slim/typescript/src/services.ts/UserService/create@28:5"},"@exit":{"kind":"exit","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"id":"can://slim/typescript/src/services.ts/UserService/create@exit"},"@formal_in:0":{"kind":"formal_in","of":"name","id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0"},"@formal_in:1":{"kind":"formal_in","of":"role","id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/create@formal_out"},"26:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"26:5","id":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_out"},"25:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"25:5","id":"can://slim/typescript/src/services.ts/UserService/create@25:5/actual_out"},"25:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"25:5","id":"can://slim/typescript/src/services.ts/UserService/create@25:5/actual_in:0"},"26:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"26:5","id":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:0"},"26:5/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"26:5","id":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:1"},"26:5/actual_in:2":{"kind":"actual_in","of":"arg2","parent":"26:5","id":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:2"},"27:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"27:5","id":"can://slim/typescript/src/services.ts/UserService/create@27:5/actual_in:0"},"27:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"27:5","id":"can://slim/typescript/src/services.ts/UserService/create@27:5/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"25:5","kind":"fallthrough"},{"src":"25:5","dst":"@exit","kind":"exception"},{"src":"25:5","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"27:5","kind":"fallthrough"},{"src":"27:5","dst":"@exit","kind":"exception"},{"src":"27:5","dst":"28:5","kind":"fallthrough"},{"src":"28:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"25:5"},{"src":"25:5","dst":"26:5"},{"src":"26:5","dst":"27:5"},{"src":"27:5","dst":"28:5"}],"ddg":[{"src":"@entry","dst":"25:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5","var":"this.startId","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5/actual_in:0","var":"this.startId","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5/actual_in:0","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"26:5","var":"name","prov":["reaching-defs"]},{"src":"@entry","dst":"26:5","var":"role","prov":["reaching-defs"]},{"src":"@entry","dst":"27:5","var":"this.users.push","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"26:5","var":"name","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"26:5/actual_in:1","var":"name","prov":["reaching-defs"]},{"src":"@formal_in:1","dst":"26:5","var":"role","prov":["reaching-defs"]},{"src":"@formal_in:1","dst":"26:5/actual_in:2","var":"role","prov":["reaching-defs"]},{"src":"25:5","dst":"26:5","var":"id","prov":["reaching-defs"]},{"src":"25:5","dst":"26:5/actual_in:0","var":"id","prov":["reaching-defs"]},{"src":"25:5/actual_out","dst":"25:5","var":"$ret","prov":["reaching-defs"]},{"src":"26:5","dst":"27:5","var":"user","prov":["reaching-defs"]},{"src":"26:5","dst":"28:5","var":"user","prov":["reaching-defs"]},{"src":"26:5/actual_out","dst":"26:5","var":"$ret","prov":["reaching-defs"]},{"src":"28:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"25:5/actual_in:0","dst":"25:5/actual_out"},{"src":"27:5/actual_in:0","dst":"27:5/actual_out"}]},"createGuest":{"id":"can://slim/typescript/src/services.ts/UserService/createGuest","kind":"method","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"name":"createGuest","signature":"src/services.UserService.createGuest","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"32:18":{"kind":"call","span":{"start":[32,18],"end":[32,50],"bytes":[919,951]},"callee":"can://slim/typescript/src/services.ts/makeGuestName","method_name":"makeGuestName","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:18"},"33:12":{"kind":"call","span":{"start":[33,12],"end":[33,41],"bytes":[964,993]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this","receiver_type":"this","argument_types":["string","Role.Guest"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:12"},"@entry":{"kind":"entry","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@entry"},"32:5":{"kind":"statement","span":{"start":[32,5],"end":[32,51],"bytes":[906,952]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5"},"33:5":{"kind":"statement","span":{"start":[33,5],"end":[33,42],"bytes":[957,994]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5"},"@exit":{"kind":"exit","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/createGuest@formal_out"},"32:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"32:5","id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5/actual_out"},"33:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"33:5","id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_out"},"32:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"32:5","id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5/actual_in:0"},"33:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"33:5","id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_in:0"},"33:5/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"33:5","id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_in:1"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"32:5","kind":"fallthrough"},{"src":"32:5","dst":"@exit","kind":"exception"},{"src":"32:5","dst":"33:5","kind":"fallthrough"},{"src":"33:5","dst":"@exit","kind":"exception"},{"src":"33:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"32:5"},{"src":"32:5","dst":"33:5"}],"ddg":[{"src":"@entry","dst":"32:5","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"32:5/actual_in:0","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"33:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"33:5","var":"this.create","prov":["reaching-defs"]},{"src":"32:5","dst":"33:5","var":"name","prov":["reaching-defs"]},{"src":"32:5","dst":"33:5/actual_in:0","var":"name","prov":["reaching-defs"]},{"src":"32:5/actual_out","dst":"32:5","var":"$ret","prov":["reaching-defs"]},{"src":"33:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]},{"src":"33:5/actual_out","dst":"33:5","var":"$ret","prov":["reaching-defs"]}],"summary":[{"src":"32:5/actual_in:0","dst":"32:5/actual_out"},{"src":"33:5","dst":"33:5","var":"src/services.nextId"},{"src":"33:5/actual_in:0","dst":"33:5/actual_out"},{"src":"33:5/actual_in:1","dst":"33:5/actual_out"}]},"describeAll":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll","kind":"method","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"name":"describeAll","signature":"src/services.UserService.describeAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:12":{"kind":"call","span":{"start":[37,12],"end":[37,47],"bytes":[1039,1074]},"callee":"can://slim/@external/(builtin)/map","method_name":"map","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["(u: User) => string"],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:12"},"@entry":{"kind":"entry","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@entry"},"37:5":{"kind":"statement","span":{"start":[37,5],"end":[37,48],"bytes":[1032,1075]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:5"},"@exit":{"kind":"exit","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/describeAll@formal_out"},"37:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"37:5","id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:5/actual_in:0"},"37:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"37:5","id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:5/actual_out"}},"callables":{"":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"arrow","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"name":"(anonymous)","signature":"src/services.UserService.describeAll.","comments":[],"decorators":[],"parameters":[{"name":"u","type":"User","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":37,"end_line":37,"start_column":28,"end_column":29,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:34":{"kind":"call","span":{"start":[37,34],"end":[37,46],"bytes":[1061,1073]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34"},"@entry":{"kind":"entry","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@entry"},"@exit":{"kind":"exit","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@exit"},"@formal_in:0":{"kind":"formal_in","of":"u","id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_out"},"37:34/actual_out":{"kind":"actual_out","of":"$ret","parent":"37:34","id":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"37:34","kind":"fallthrough"},{"src":"37:34","dst":"@exit","kind":"exception"},{"src":"37:34","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"37:34"}],"ddg":[{"src":"@entry","dst":"37:34","var":"u.describe","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"37:34","var":"u.describe","prov":["reaching-defs"]},{"src":"37:34","dst":"@formal_out","var":"return","prov":["reaching-defs"]},{"src":"37:34/actual_out","dst":"37:34","var":"$ret","prov":["reaching-defs"]}],"summary":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"37:5","kind":"fallthrough"},{"src":"37:5","dst":"@exit","kind":"exception"},{"src":"37:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"37:5"}],"ddg":[{"src":"@entry","dst":"37:5","var":"this.users.map","prov":["reaching-defs"]},{"src":"37:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"37:5/actual_in:0","dst":"37:5/actual_out"}]},"loginAll":{"id":"can://slim/typescript/src/services.ts/UserService/loginAll","kind":"method","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"name":"loginAll","signature":"src/services.UserService.loginAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"43:22":{"kind":"call","span":{"start":[43,22],"end":[43,37],"bytes":[1193,1208]},"callee":"can://slim/typescript/src/models.ts/User/recordLogin","method_name":"recordLogin","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"Promise","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:22"},"@entry":{"kind":"entry","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@entry"},"41:5":{"kind":"statement","span":{"start":[41,5],"end":[41,19],"bytes":[1123,1137]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@41:5"},"42:5":{"kind":"statement","span":{"start":[42,5],"end":[44,6],"bytes":[1142,1215]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@42:5"},"43:7":{"kind":"statement","span":{"start":[43,7],"end":[43,38],"bytes":[1178,1209]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:7"},"45:5":{"kind":"statement","span":{"start":[45,5],"end":[45,18],"bytes":[1220,1233]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@45:5"},"@exit":{"kind":"exit","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/loginAll@formal_out"},"43:7/actual_out":{"kind":"actual_out","of":"$ret","parent":"43:7","id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:7/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"41:5","kind":"fallthrough"},{"src":"41:5","dst":"42:5","kind":"fallthrough"},{"src":"42:5","dst":"43:7","kind":"true"},{"src":"42:5","dst":"45:5","kind":"false"},{"src":"43:7","dst":"@exit","kind":"exception"},{"src":"43:7","dst":"42:5","kind":"loop_back"},{"src":"45:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"41:5"},{"src":"@entry","dst":"42:5"},{"src":"42:5","dst":"43:7"},{"src":"42:5","dst":"45:5"},{"src":"43:7","dst":"42:5"}],"ddg":[{"src":"@entry","dst":"42:5","var":"this.users","prov":["reaching-defs"]},{"src":"41:5","dst":"43:7","var":"total","prov":["reaching-defs"]},{"src":"41:5","dst":"45:5","var":"total","prov":["reaching-defs"]},{"src":"42:5","dst":"43:7","var":"u.recordLogin","prov":["reaching-defs"]},{"src":"43:7","dst":"43:7","var":"total","prov":["reaching-defs"]},{"src":"43:7","dst":"45:5","var":"total","prov":["reaching-defs"]},{"src":"43:7/actual_out","dst":"43:7","var":"$ret","prov":["reaching-defs"]},{"src":"45:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"constructor":{"id":"can://slim/typescript/src/services.ts/UserService/constructor","kind":"constructor","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"name":"constructor","signature":"src/services.UserService.constructor","comments":[],"decorators":[],"parameters":[{"name":"startId","type":"number","default_value":"0","is_optional":true,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":22,"end_line":22,"start_column":15,"end_column":51,"id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"id":"can://slim/typescript/src/services.ts/UserService/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"id":"can://slim/typescript/src/services.ts/UserService/constructor@exit"},"@formal_in:0":{"kind":"formal_in","of":"startId","id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[],"summary":[]}},"fields":{"users":{"id":"can://slim/typescript/src/services.ts/UserService/users","kind":"field","span":{"start":[20,3],"end":[20,30],"bytes":[587,614]},"name":"users","type":"User[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"startId":{"id":"can://slim/typescript/src/services.ts/UserService/startId","kind":"field","name":"startId","type":"number","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"makeGuestName":{"id":"can://slim/typescript/src/services.ts/makeGuestName","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"name":"makeGuestName","signature":"src/services.makeGuestName","comments":[{"content":"Pure helper — top-level function.","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41}],"decorators":[],"parameters":[{"name":"seed","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":31,"end_column":43,"id":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"id":"can://slim/typescript/src/services.ts/makeGuestName@entry"},"5:3":{"kind":"statement","span":{"start":[5,3],"end":[5,26],"bytes":[164,187]},"id":"can://slim/typescript/src/services.ts/makeGuestName@5:3"},"@exit":{"kind":"exit","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"id":"can://slim/typescript/src/services.ts/makeGuestName@exit"},"@formal_in:0":{"kind":"formal_in","of":"seed","id":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/makeGuestName@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:3","kind":"fallthrough"},{"src":"5:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:3"}],"ddg":[{"src":"@entry","dst":"5:3","var":"seed","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"5:3","var":"seed","prov":["reaching-defs"]},{"src":"5:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"announce":{"id":"can://slim/typescript/src/services.ts/announce","kind":"function","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"name":"announce","signature":"src/services.announce","comments":[{"content":"Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\nconcrete implementer of Named (User, Robot, ...).","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4}],"decorators":[],"parameters":[{"name":"thing","type":"Named","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":12,"end_line":12,"start_column":26,"end_column":38,"id":"can://slim/typescript/src/services.ts/announce@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"13:10":{"kind":"call","span":{"start":[13,10],"end":[13,26],"bytes":[407,423]},"callee":"can://slim/typescript/src/models.ts/Named/describe","method_name":"describe","receiver_expr":"thing","receiver_type":"Named","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/announce@13:10"},"@entry":{"kind":"entry","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"id":"can://slim/typescript/src/services.ts/announce@entry"},"13:3":{"kind":"statement","span":{"start":[13,3],"end":[13,27],"bytes":[400,424]},"id":"can://slim/typescript/src/services.ts/announce@13:3"},"@exit":{"kind":"exit","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"id":"can://slim/typescript/src/services.ts/announce@exit"},"@formal_in:0":{"kind":"formal_in","of":"thing","id":"can://slim/typescript/src/services.ts/announce@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/announce@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"13:3","kind":"fallthrough"},{"src":"13:3","dst":"@exit","kind":"exception"},{"src":"13:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"13:3"}],"ddg":[{"src":"@entry","dst":"13:3","var":"thing.describe","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"13:3","var":"thing.describe","prov":["reaching-defs"]},{"src":"13:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"nextId":{"id":"can://slim/typescript/src/services.ts/nextId","kind":"arrow","span":{"start":[17,14],"end":[17,51],"bytes":[518,555]},"name":"nextId","signature":"src/services.nextId","comments":[],"decorators":[],"parameters":[{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":17,"end_line":17,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/services.ts/nextId@formal_in:0"}],"type_parameters":[],"return_type":"UserId","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[17,23],"end":[17,51],"bytes":[527,555]},"id":"can://slim/typescript/src/services.ts/nextId@entry"},"17:46":{"kind":"statement","span":{"start":[17,46],"end":[17,51],"bytes":[550,555]},"id":"can://slim/typescript/src/services.ts/nextId@17:46"},"@exit":{"kind":"exit","span":{"start":[17,23],"end":[17,51],"bytes":[527,555]},"id":"can://slim/typescript/src/services.ts/nextId@exit"},"@formal_in:0":{"kind":"formal_in","of":"n","id":"can://slim/typescript/src/services.ts/nextId@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/nextId@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"17:46","kind":"fallthrough"},{"src":"17:46","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"17:46"}],"ddg":[{"src":"@entry","dst":"17:46","var":"n","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"17:46","var":"n","prov":["reaching-defs"]},{"src":"17:46","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"1bda3666dab48f8e686fb8ffc2143f2e422af62be46698053cfeea4184b55617"},"src/util.ts":{"id":"can://slim/typescript/src/util.ts","kind":"module","span":{"start":[1,1],"end":[35,1],"bytes":[0,949]},"source":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */\nexport namespace StringUtil {\n export function repeat(s: string, n: number): string {\n return slug(s).repeat(n);\n }\n\n export function slug(s: string): string {\n return s.toLowerCase().replace(/\\s+/g, \"-\");\n }\n\n export class Builder {\n private parts: string[] = [];\n add(part: string): this {\n this.parts.push(slug(part));\n return this;\n }\n build(): string {\n return this.parts.join(\"/\");\n }\n }\n}\n\n/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */\nexport function classify(items: T[]): Record {\n function keyOf(item: T): string {\n return item.name.charAt(0);\n }\n const out: Record = {};\n for (const item of items) {\n const k = keyOf(item);\n (out[k] ??= []).push(item);\n }\n return out;\n}\n","imports":[],"exports":[],"comments":[{"content":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106},{"content":"/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"types":{"StringUtil":{"id":"can://slim/typescript/src/util.ts/StringUtil","kind":"namespace","span":{"start":[2,1],"end":[21,2],"bytes":[106,543]},"name":"StringUtil","signature":"src/util.StringUtil","comments":[{"content":"A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106}],"types":{"Builder":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder","kind":"class","span":{"start":[11,3],"end":[20,4],"bytes":[328,541]},"name":"Builder","signature":"src/util.StringUtil.Builder","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"add":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","kind":"method","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"name":"add","signature":"src/util.StringUtil.Builder.add","comments":[],"decorators":[],"parameters":[{"name":"part","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":13,"end_line":13,"start_column":9,"end_column":21,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0"}],"type_parameters":[],"return_type":"this","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"14:7":{"kind":"call","span":{"start":[14,7],"end":[14,34],"bytes":[421,448]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["string"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7"},"14:23":{"kind":"call","span":{"start":[14,23],"end":[14,33],"bytes":[437,447]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:23"},"@entry":{"kind":"entry","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@entry"},"15:7":{"kind":"statement","span":{"start":[15,7],"end":[15,19],"bytes":[456,468]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@15:7"},"@exit":{"kind":"exit","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@exit"},"@formal_in:0":{"kind":"formal_in","of":"part","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_out"},"14:7/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"14:7","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7/actual_in:0"},"14:7/actual_out":{"kind":"actual_out","of":"$ret","parent":"14:7","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"14:7","kind":"fallthrough"},{"src":"14:7","dst":"@exit","kind":"exception"},{"src":"14:7","dst":"15:7","kind":"fallthrough"},{"src":"15:7","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"14:7"},{"src":"14:7","dst":"15:7"}],"ddg":[{"src":"@entry","dst":"14:7","var":"part","prov":["reaching-defs"]},{"src":"@entry","dst":"14:7","var":"this.parts.push","prov":["reaching-defs"]},{"src":"@entry","dst":"15:7","var":"this","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"14:7","var":"part","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"14:7/actual_in:0","var":"part","prov":["reaching-defs"]},{"src":"14:7/actual_out","dst":"14:7","var":"$ret","prov":["reaching-defs"]},{"src":"15:7","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"14:7/actual_in:0","dst":"14:7/actual_out"}]},"build":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","kind":"method","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"name":"build","signature":"src/util.StringUtil.Builder.build","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"18:14":{"kind":"call","span":{"start":[18,14],"end":[18,34],"bytes":[510,530]},"callee":"can://slim/@external/(builtin)/join","method_name":"join","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["\"/\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:14"},"@entry":{"kind":"entry","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@entry"},"18:7":{"kind":"statement","span":{"start":[18,7],"end":[18,35],"bytes":[503,531]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:7"},"@exit":{"kind":"exit","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@formal_out"},"18:7/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"18:7","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:7/actual_in:0"},"18:7/actual_out":{"kind":"actual_out","of":"$ret","parent":"18:7","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:7/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"18:7","kind":"fallthrough"},{"src":"18:7","dst":"@exit","kind":"exception"},{"src":"18:7","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"18:7"}],"ddg":[{"src":"@entry","dst":"18:7","var":"this.parts.join","prov":["reaching-defs"]},{"src":"18:7","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"18:7/actual_in:0","dst":"18:7/actual_out"}]},"constructor":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","kind":"constructor","span":{"start":[0,0],"end":[0,0],"bytes":[0,0]},"name":"constructor","signature":"src/util.StringUtil.Builder.constructor","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":true,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"parts":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/parts","kind":"field","span":{"start":[12,5],"end":[12,34],"bytes":[355,384]},"name":"parts","type":"string[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"repeat":{"id":"can://slim/typescript/src/util.ts/StringUtil/repeat","kind":"function","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"name":"repeat","signature":"src/util.StringUtil.repeat","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":26,"end_column":35,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0"},{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":37,"end_column":46,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"4:12":{"kind":"call","span":{"start":[4,12],"end":[4,29],"bytes":[204,221]},"callee":"can://slim/@external/(builtin)/repeat","method_name":"repeat","receiver_expr":"slug(s)","receiver_type":"string","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12"},"4:12/2":{"kind":"call","span":{"start":[4,12],"end":[4,19],"bytes":[204,211]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12/2"},"@entry":{"kind":"entry","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@entry"},"4:5":{"kind":"statement","span":{"start":[4,5],"end":[4,30],"bytes":[197,222]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5"},"@exit":{"kind":"exit","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@exit"},"@formal_in:0":{"kind":"formal_in","of":"s","id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0"},"@formal_in:1":{"kind":"formal_in","of":"n","id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_out"},"4:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"4:5","id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5/actual_in:0"},"4:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"4:5","id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"4:5","kind":"fallthrough"},{"src":"4:5","dst":"@exit","kind":"exception"},{"src":"4:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"4:5"}],"ddg":[{"src":"@entry","dst":"4:5","var":"n","prov":["reaching-defs"]},{"src":"@entry","dst":"4:5","var":"s","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"4:5","var":"s","prov":["reaching-defs"]},{"src":"@formal_in:1","dst":"4:5","var":"n","prov":["reaching-defs"]},{"src":"@formal_in:1","dst":"4:5/actual_in:0","var":"n","prov":["reaching-defs"]},{"src":"4:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]},{"src":"4:5/actual_out","dst":"4:5","var":"$ret","prov":["reaching-defs"]}],"summary":[{"src":"4:5/actual_in:0","dst":"4:5/actual_out"}]},"slug":{"id":"can://slim/typescript/src/util.ts/StringUtil/slug","kind":"function","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"name":"slug","signature":"src/util.StringUtil.slug","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"8:12":{"kind":"call","span":{"start":[8,12],"end":[8,48],"bytes":[283,319]},"callee":"can://slim/@external/(builtin)/replace","method_name":"replace","receiver_expr":"s.toLowerCase()","receiver_type":"string","argument_types":["RegExp","\"-\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12"},"8:12/2":{"kind":"call","span":{"start":[8,12],"end":[8,27],"bytes":[283,298]},"callee":"can://slim/@external/(builtin)/toLowerCase","method_name":"toLowerCase","receiver_expr":"s","receiver_type":"string","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12/2"},"@entry":{"kind":"entry","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@entry"},"8:5":{"kind":"statement","span":{"start":[8,5],"end":[8,49],"bytes":[276,320]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:5"},"@exit":{"kind":"exit","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@exit"},"@formal_in:0":{"kind":"formal_in","of":"s","id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_out"},"8:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"8:5","id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:5/actual_in:0"},"8:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"8:5","id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:5/actual_out"},"8:5/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"8:5","id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:5/actual_in:1"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:5","kind":"fallthrough"},{"src":"8:5","dst":"@exit","kind":"exception"},{"src":"8:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:5"}],"ddg":[{"src":"@entry","dst":"8:5","var":"s.toLowerCase","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"8:5","var":"s.toLowerCase","prov":["reaching-defs"]},{"src":"8:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"8:5/actual_in:0","dst":"8:5/actual_out"},{"src":"8:5/actual_in:1","dst":"8:5/actual_out"}]}},"fields":{},"is_exported":true,"is_ambient":false}},"functions":{"classify":{"id":"can://slim/typescript/src/util.ts/classify","kind":"function","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"name":"classify","signature":"src/util.classify","comments":[{"content":"Generic top-level function with a nested helper, to exercise inner_callables + generics.","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"decorators":[],"parameters":[{"name":"items","type":"T[]","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":54,"end_column":64,"id":"can://slim/typescript/src/util.ts/classify@formal_in:0"}],"type_parameters":[{"name":"T","constraint":"{ name: string }"}],"return_type":"Record","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"30:15":{"kind":"call","span":{"start":[30,15],"end":[30,26],"bytes":[884,895]},"callee":"can://slim/typescript/src/util.ts/classify/keyOf","method_name":"keyOf","argument_types":["T"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@30:15"},"31:5":{"kind":"call","span":{"start":[31,5],"end":[31,31],"bytes":[901,927]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"(out[k] ??= [])","receiver_type":"T[]","argument_types":["T"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@31:5"},"@entry":{"kind":"entry","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"id":"can://slim/typescript/src/util.ts/classify@entry"},"25:3":{"kind":"statement","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify@25:3"},"28:3":{"kind":"statement","span":{"start":[28,3],"end":[28,39],"bytes":[803,839]},"id":"can://slim/typescript/src/util.ts/classify@28:3"},"29:3":{"kind":"statement","span":{"start":[29,3],"end":[32,4],"bytes":[842,932]},"id":"can://slim/typescript/src/util.ts/classify@29:3"},"30:5":{"kind":"statement","span":{"start":[30,5],"end":[30,27],"bytes":[874,896]},"id":"can://slim/typescript/src/util.ts/classify@30:5"},"33:3":{"kind":"statement","span":{"start":[33,3],"end":[33,14],"bytes":[935,946]},"id":"can://slim/typescript/src/util.ts/classify@33:3"},"@exit":{"kind":"exit","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"id":"can://slim/typescript/src/util.ts/classify@exit"},"@formal_in:0":{"kind":"formal_in","of":"items","id":"can://slim/typescript/src/util.ts/classify@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/classify@formal_out"},"30:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"30:5","id":"can://slim/typescript/src/util.ts/classify@30:5/actual_in:0"},"30:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"30:5","id":"can://slim/typescript/src/util.ts/classify@30:5/actual_out"},"31:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"31:5","id":"can://slim/typescript/src/util.ts/classify@31:5/actual_in:0"},"31:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"31:5","id":"can://slim/typescript/src/util.ts/classify@31:5/actual_out"}},"callables":{"keyOf":{"id":"can://slim/typescript/src/util.ts/classify/keyOf","kind":"function","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"name":"keyOf","signature":"src/util.classify.keyOf","comments":[],"decorators":[],"parameters":[{"name":"item","type":"T","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":25,"end_line":25,"start_column":18,"end_column":25,"id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,31],"bytes":[776,795]},"callee":"can://slim/@external/(builtin)/charAt","method_name":"charAt","receiver_expr":"item.name","receiver_type":"string","argument_types":["0"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:12"},"@entry":{"kind":"entry","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@entry"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,32],"bytes":[769,796]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:5"},"@exit":{"kind":"exit","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@exit"},"@formal_in:0":{"kind":"formal_in","of":"item","id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_out"},"26:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"26:5","id":"can://slim/typescript/src/util.ts/classify/keyOf@26:5/actual_in:0"},"26:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"26:5","id":"can://slim/typescript/src/util.ts/classify/keyOf@26:5/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"26:5"}],"ddg":[{"src":"@entry","dst":"26:5","var":"item.name.charAt","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"26:5","var":"item.name.charAt","prov":["reaching-defs"]},{"src":"26:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"26:5/actual_in:0","dst":"26:5/actual_out"}]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"25:3","kind":"fallthrough"},{"src":"25:3","dst":"@exit","kind":"exception"},{"src":"25:3","dst":"28:3","kind":"fallthrough"},{"src":"28:3","dst":"29:3","kind":"fallthrough"},{"src":"29:3","dst":"30:5","kind":"true"},{"src":"29:3","dst":"33:3","kind":"false"},{"src":"30:5","dst":"@exit","kind":"exception"},{"src":"30:5","dst":"31:5","kind":"fallthrough"},{"src":"31:5","dst":"@exit","kind":"exception"},{"src":"31:5","dst":"29:3","kind":"loop_back"},{"src":"33:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"25:3"},{"src":"25:3","dst":"28:3"},{"src":"25:3","dst":"29:3"},{"src":"29:3","dst":"30:5"},{"src":"29:3","dst":"33:3"},{"src":"30:5","dst":"31:5"},{"src":"31:5","dst":"29:3"}],"ddg":[{"src":"@entry","dst":"29:3","var":"items","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"29:3","var":"items","prov":["reaching-defs"]},{"src":"28:3","dst":"31:5","var":"out[*]","prov":["reaching-defs"]},{"src":"28:3","dst":"33:3","var":"out","prov":["reaching-defs"]},{"src":"29:3","dst":"30:5","var":"item","prov":["reaching-defs"]},{"src":"29:3","dst":"30:5/actual_in:0","var":"item","prov":["reaching-defs"]},{"src":"29:3","dst":"31:5","var":"item","prov":["reaching-defs"]},{"src":"30:5","dst":"31:5","var":"k","prov":["reaching-defs"]},{"src":"30:5/actual_out","dst":"30:5","var":"$ret","prov":["reaching-defs"]},{"src":"31:5","dst":"31:5","var":"out[*]","prov":["reaching-defs"]},{"src":"31:5","dst":"33:3","var":"out","prov":["reaching-defs"]},{"src":"33:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"30:5/actual_in:0","dst":"30:5/actual_out"},{"src":"31:5/actual_in:0","dst":"31:5/actual_out"}]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"54886cff7e11ccadc987571f508b2aef2f324b14e63d8ad52100499851d130fa"}},"call_graph":[{"src":"can://slim/typescript/src/controllers.ts","dst":"can://slim/typescript/src/controllers.ts/Controller","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/index.ts","dst":"can://slim/typescript/src/index.ts/main","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Param","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/services.ts/UserService/describeAll","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/createGuest","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/list","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/show","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/announce","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/Robot/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/@external/(builtin)/log","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/models.ts/User/constructor","dst":"can://slim/typescript/src/models.ts/Entity/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Named/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Robot/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/services.ts/nextId","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/makeGuestName","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/@external/(builtin)/map","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll/","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/loginAll","dst":"can://slim/typescript/src/models.ts/User/recordLogin","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/typescript/src/util.ts/classify/keyOf","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify/keyOf","dst":"can://slim/@external/(builtin)/charAt","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/@external/(builtin)/repeat","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/replace","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/toLowerCase","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","dst":"can://slim/@external/(builtin)/join","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/typescript/src/services.ts/UserService/describeAll/","prov":["defuse"],"weight":1}],"param_in":[{"src":"can://slim/typescript/src/controllers.ts/UserController/show@20:5","dst":"can://slim/typescript/src/services.ts/UserService/create@entry","var":"src/services.nextId"},{"src":"can://slim/typescript/src/controllers.ts/UserController/show@20:5/actual_in:0","dst":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0","var":"name"},{"src":"can://slim/typescript/src/index.ts/main@11:3/actual_in:0","dst":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0","var":"service"},{"src":"can://slim/typescript/src/index.ts/main@13:3","dst":"can://slim/typescript/src/controllers.ts/UserController/show@entry","var":"src/services.nextId"},{"src":"can://slim/typescript/src/index.ts/main@13:3/actual_in:0","dst":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0","var":"id"},{"src":"can://slim/typescript/src/index.ts/main@16:3/actual_in:0","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0","var":"id"},{"src":"can://slim/typescript/src/index.ts/main@16:3/actual_in:0","dst":"can://slim/typescript/src/services.ts/announce@formal_in:0","var":"thing"},{"src":"can://slim/typescript/src/index.ts/main@16:3/actual_in:1","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1","var":"name"},{"src":"can://slim/typescript/src/index.ts/main@16:3/actual_in:2","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2","var":"role"},{"src":"can://slim/typescript/src/index.ts/main@17:3/actual_in:0","dst":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0","var":"name"},{"src":"can://slim/typescript/src/index.ts/main@17:3/actual_in:0","dst":"can://slim/typescript/src/services.ts/announce@formal_in:0","var":"thing"},{"src":"can://slim/typescript/src/index.ts/main@19:3/actual_in:0","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0","var":"s"},{"src":"can://slim/typescript/src/index.ts/main@19:3/actual_in:1","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1","var":"n"},{"src":"can://slim/typescript/src/index.ts/main@21:3/actual_in:0","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0","var":"part"},{"src":"can://slim/typescript/src/index.ts/main@7:3/actual_in:0","dst":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0","var":"startId"},{"src":"can://slim/typescript/src/index.ts/main@8:3","dst":"can://slim/typescript/src/services.ts/UserService/create@entry","var":"src/services.nextId"},{"src":"can://slim/typescript/src/index.ts/main@8:3/actual_in:0","dst":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0","var":"name"},{"src":"can://slim/typescript/src/index.ts/main@8:3/actual_in:1","dst":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1","var":"role"},{"src":"can://slim/typescript/src/index.ts/main@9:3","dst":"can://slim/typescript/src/services.ts/UserService/createGuest@entry","var":"src/services.nextId"},{"src":"can://slim/typescript/src/models.ts/User/constructor@40:5/actual_in:0","dst":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0","var":"id"},{"src":"can://slim/typescript/src/services.ts/UserService/create@25:5/actual_in:0","dst":"can://slim/typescript/src/services.ts/nextId@formal_in:0","var":"n"},{"src":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:0","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0","var":"id"},{"src":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:1","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1","var":"name"},{"src":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:2","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2","var":"role"},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5/actual_in:0","dst":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0","var":"seed"},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5","dst":"can://slim/typescript/src/services.ts/UserService/create@entry","var":"src/services.nextId"},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_in:0","dst":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0","var":"name"},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_in:1","dst":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1","var":"role"},{"src":"can://slim/typescript/src/util.ts/classify@30:5/actual_in:0","dst":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0","var":"item"},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7/actual_in:0","dst":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0","var":"s"},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5/actual_in:0","dst":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0","var":"s"}],"param_out":[{"src":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_out","dst":"can://slim/typescript/src/index.ts/main@11:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/controllers.ts/UserController/list@formal_out","dst":"can://slim/typescript/src/index.ts/main@12:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/controllers.ts/UserController/show@formal_out","dst":"can://slim/typescript/src/index.ts/main@13:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/Entity/constructor@formal_out","dst":"can://slim/typescript/src/models.ts/User/constructor@40:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/Robot/constructor@formal_out","dst":"can://slim/typescript/src/index.ts/main@17:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/User/constructor@formal_out","dst":"can://slim/typescript/src/index.ts/main@16:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/User/constructor@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/User/describe@formal_out","dst":"can://slim/typescript/src/controllers.ts/UserController/show@21:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/User/describe@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/User/recordLogin@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/loginAll@43:7/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/announce@formal_out","dst":"can://slim/typescript/src/index.ts/main@16:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/announce@formal_out","dst":"can://slim/typescript/src/index.ts/main@17:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/makeGuestName@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/nextId@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/create@25:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/constructor@formal_out","dst":"can://slim/typescript/src/index.ts/main@7:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/create@formal_out","dst":"can://slim/typescript/src/controllers.ts/UserController/show@20:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/create@formal_out","dst":"can://slim/typescript/src/index.ts/main@8:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/create@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest@formal_out","dst":"can://slim/typescript/src/index.ts/main@9:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll@formal_out","dst":"can://slim/typescript/src/controllers.ts/UserController/list@26:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/classify/keyOf@formal_out","dst":"can://slim/typescript/src/util.ts/classify@30:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_out","dst":"can://slim/typescript/src/index.ts/main@21:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@formal_out","dst":"can://slim/typescript/src/index.ts/main@21:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_out","dst":"can://slim/typescript/src/index.ts/main@19:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_out","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_out","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5/actual_out","var":"$ret"}],"artifacts":{"package.json":{"id":"can://slim/artifact/package.json","kind":"artifact","path":"package.json","format":"json","roles":["dependency-manifest","tool-config"],"size_bytes":88,"sha256":"277f174033b3f17dcd3ba9a550b53289624f034606303cef18a3f84ab7156c67","source":"{\n \"name\": \"sample-app\",\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"private\": true\n}\n","extraction":"none","config_keys":[]},"tsconfig.json":{"id":"can://slim/artifact/tsconfig.json","kind":"artifact","path":"tsconfig.json","format":"json","roles":["tool-config"],"size_bytes":289,"sha256":"72f24fc616456ab556dd8e7c886264214cb344547b32b972eb476467af0a9cab","source":"{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"experimentalDecorators\": true,\n \"emitDecoratorMetadata\": true\n },\n \"include\": [\"src/**/*.ts\"]\n}\n","extraction":"full","config_keys":[{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.target","key":"compilerOptions.target","namespace":"json","value":"ES2022","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.module","key":"compilerOptions.module","namespace":"json","value":"ESNext","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.moduleResolution","key":"compilerOptions.moduleResolution","namespace":"json","value":"bundler","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.strict","key":"compilerOptions.strict","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.esModuleInterop","key":"compilerOptions.esModuleInterop","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.skipLibCheck","key":"compilerOptions.skipLibCheck","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.experimentalDecorators","key":"compilerOptions.experimentalDecorators","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.emitDecoratorMetadata","key":"compilerOptions.emitDecoratorMetadata","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/include.0","key":"include.0","namespace":"json","value":"src/**/*.ts","references":[]}]}},"dependencies":[],"unresolved_imports":[],"config_uses":[],"config_reads":[],"entrypoint_report":{"frameworks_detected":[],"rulesets":["shipped"],"unresolved":{"Get":2,"Controller":1},"errors":[]},"external_symbols":{"can://slim/@external/(builtin)/log":{"id":"can://slim/@external/(builtin)/log","kind":"external","module":"(builtin)","name":"log"},"can://slim/@external/(builtin)/push":{"id":"can://slim/@external/(builtin)/push","kind":"external","module":"(builtin)","name":"push"},"can://slim/@external/(builtin)/map":{"id":"can://slim/@external/(builtin)/map","kind":"external","module":"(builtin)","name":"map"},"can://slim/@external/(builtin)/charAt":{"id":"can://slim/@external/(builtin)/charAt","kind":"external","module":"(builtin)","name":"charAt"},"can://slim/@external/(builtin)/repeat":{"id":"can://slim/@external/(builtin)/repeat","kind":"external","module":"(builtin)","name":"repeat"},"can://slim/@external/(builtin)/replace":{"id":"can://slim/@external/(builtin)/replace","kind":"external","module":"(builtin)","name":"replace"},"can://slim/@external/(builtin)/toLowerCase":{"id":"can://slim/@external/(builtin)/toLowerCase","kind":"external","module":"(builtin)","name":"toLowerCase"},"can://slim/@external/(builtin)/join":{"id":"can://slim/@external/(builtin)/join","kind":"external","module":"(builtin)","name":"join"}},"synthesized_callables":{"can://slim/typescript/src/controllers.ts/Controller@5:10":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Get@8:10":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Param@11:10":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"callable"},"can://slim/typescript/src/services.ts/UserService/describeAll@37:27":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"callable"}}}} \ No newline at end of file +{"schema_version":"2.0.0","language":"typescript","max_level":4,"k_limit":3,"analyzer":{"name":"codeanalyzer-typescript","version":"1.6.0"},"application":{"id":"can://slim","kind":"application","symbol_table":{"src/controllers.ts":{"id":"can://slim/typescript/src/controllers.ts","kind":"module","span":{"start":[1,1],"end":[29,1],"bytes":[0,699]},"source":"import { UserService } from \"./services\";\n\n// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.\nfunction Controller(prefix: string): ClassDecorator {\n return () => undefined;\n}\nfunction Get(path: string): MethodDecorator {\n return () => undefined;\n}\nfunction Param(name: string): ParameterDecorator {\n return () => undefined;\n}\n\n@Controller(\"/users\")\nexport class UserController {\n constructor(private readonly service: UserService) {}\n\n @Get(\"/:id\")\n show(@Param(\"id\") id: string): string {\n const user = this.service.create(id);\n return user.describe();\n }\n\n @Get(\"/\")\n list(): string[] {\n return this.service.describeAll();\n }\n}\n","imports":[{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":42,"resolved_module":"src/services.ts"}],"exports":[],"comments":[{"content":"// Minimal decorator factories (NestJS/Angular-flavored) to exercise structured TSDecorator capture.","is_docstring":false,"start_line":3,"end_line":3,"start_column":1,"end_column":101}],"types":{"UserController":{"id":"can://slim/typescript/src/controllers.ts/UserController","kind":"class","span":{"start":[14,1],"end":[28,2],"bytes":[380,698]},"name":"UserController","signature":"src/controllers.UserController","comments":[],"decorators":[{"name":"Controller","positional_arguments":["\"/users\""],"keyword_arguments":{},"start_line":14,"end_line":14,"start_column":1,"end_column":22}],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"show":{"id":"can://slim/typescript/src/controllers.ts/UserController/show","kind":"method","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"name":"show","signature":"src/controllers.UserController.show","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/:id\""],"keyword_arguments":{},"start_line":18,"end_line":18,"start_column":3,"end_column":15}],"parameters":[{"name":"id","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[{"name":"Param","positional_arguments":["\"id\""],"keyword_arguments":{},"start_line":19,"end_line":19,"start_column":8,"end_column":20}],"start_line":19,"end_line":19,"start_column":8,"end_column":31,"id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"20:18":{"kind":"call","span":{"start":[20,18],"end":[20,41],"bytes":[563,586]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this.service","receiver_type":"UserService","argument_types":["string"],"type_arguments":[],"return_type":"import(\"./models\").User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:18"},"21:12":{"kind":"call","span":{"start":[21,12],"end":[21,27],"bytes":[599,614]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"user","receiver_type":"import(\"./models\").User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:12"},"19:9":{"kind":"call","span":{"start":[19,9],"end":[19,20],"bytes":[512,523]},"callee":"can://slim/typescript/src/controllers.ts/Param","method_name":"Param","argument_types":["\"id\""],"type_arguments":[],"return_type":"ParameterDecorator","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/show@19:9"},"@entry":{"kind":"entry","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@entry"},"20:5":{"kind":"statement","span":{"start":[20,5],"end":[20,42],"bytes":[550,587]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@20:5"},"21:5":{"kind":"statement","span":{"start":[21,5],"end":[21,28],"bytes":[592,615]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@21:5"},"@exit":{"kind":"exit","span":{"start":[18,3],"end":[22,4],"bytes":[491,619]},"id":"can://slim/typescript/src/controllers.ts/UserController/show@exit"},"@formal_in:0":{"kind":"formal_in","of":"id","id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/UserController/show@formal_out"},"20:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"20:5","id":"can://slim/typescript/src/controllers.ts/UserController/show@20:5/actual_in:0"},"20:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"20:5","id":"can://slim/typescript/src/controllers.ts/UserController/show@20:5/actual_out"},"21:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"21:5","id":"can://slim/typescript/src/controllers.ts/UserController/show@21:5/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"20:5","kind":"fallthrough"},{"src":"20:5","dst":"@exit","kind":"exception"},{"src":"20:5","dst":"21:5","kind":"fallthrough"},{"src":"21:5","dst":"@exit","kind":"exception"},{"src":"21:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"20:5"},{"src":"20:5","dst":"21:5"}],"ddg":[{"src":"@entry","dst":"20:5","var":"id","prov":["reaching-defs"]},{"src":"@entry","dst":"20:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"20:5","var":"this.service.create","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"20:5","var":"id","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"20:5/actual_in:0","var":"id","prov":["reaching-defs"]},{"src":"20:5","dst":"21:5","var":"user.describe","prov":["reaching-defs"]},{"src":"20:5/actual_out","dst":"20:5","var":"$ret","prov":["reaching-defs"]},{"src":"21:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]},{"src":"21:5/actual_out","dst":"21:5","var":"$ret","prov":["reaching-defs"]}],"summary":[{"src":"20:5","dst":"20:5","var":"src/services.nextId"},{"src":"20:5/actual_in:0","dst":"20:5/actual_out"}]},"list":{"id":"can://slim/typescript/src/controllers.ts/UserController/list","kind":"method","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"name":"list","signature":"src/controllers.UserController.list","comments":[],"decorators":[{"name":"Get","positional_arguments":["\"/\""],"keyword_arguments":{},"start_line":24,"end_line":24,"start_column":3,"end_column":12}],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,38],"bytes":[665,691]},"callee":"can://slim/typescript/src/services.ts/UserService/describeAll","method_name":"describeAll","receiver_expr":"this.service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:12"},"@entry":{"kind":"entry","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@entry"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,39],"bytes":[658,692]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@26:5"},"@exit":{"kind":"exit","span":{"start":[24,3],"end":[27,4],"bytes":[623,696]},"id":"can://slim/typescript/src/controllers.ts/UserController/list@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/UserController/list@formal_out"},"26:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"26:5","id":"can://slim/typescript/src/controllers.ts/UserController/list@26:5/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"26:5"}],"ddg":[{"src":"@entry","dst":"26:5","var":"this.service.describeAll","prov":["reaching-defs"]},{"src":"26:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]},{"src":"26:5/actual_out","dst":"26:5","var":"$ret","prov":["reaching-defs"]}],"summary":[]},"constructor":{"id":"can://slim/typescript/src/controllers.ts/UserController/constructor","kind":"constructor","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"name":"constructor","signature":"src/controllers.UserController.constructor","comments":[],"decorators":[],"parameters":[{"name":"service","type":"UserService","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":16,"end_line":16,"start_column":15,"end_column":52,"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[16,3],"end":[16,56],"bytes":[434,487]},"id":"can://slim/typescript/src/controllers.ts/UserController/constructor@exit"},"@formal_in:0":{"kind":"formal_in","of":"service","id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[],"summary":[]}},"fields":{"service":{"id":"can://slim/typescript/src/controllers.ts/UserController/service","kind":"field","name":"service","type":"UserService","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"Controller":{"id":"can://slim/typescript/src/controllers.ts/Controller","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"name":"Controller","signature":"src/controllers.Controller","comments":[],"decorators":[],"parameters":[{"name":"prefix","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":21,"end_column":35,"id":"can://slim/typescript/src/controllers.ts/Controller@formal_in:0"}],"type_parameters":[],"return_type":"ClassDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"id":"can://slim/typescript/src/controllers.ts/Controller@entry"},"5:3":{"kind":"statement","span":{"start":[5,3],"end":[5,26],"bytes":[200,223]},"id":"can://slim/typescript/src/controllers.ts/Controller@5:3"},"@exit":{"kind":"exit","span":{"start":[4,1],"end":[6,2],"bytes":[144,225]},"id":"can://slim/typescript/src/controllers.ts/Controller@exit"},"@formal_in:0":{"kind":"formal_in","of":"prefix","id":"can://slim/typescript/src/controllers.ts/Controller@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Controller@formal_out"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"arrow","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"name":"(anonymous)","signature":"src/controllers.Controller.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@entry"},"5:16":{"kind":"statement","span":{"start":[5,16],"end":[5,25],"bytes":[213,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@5:16"},"@exit":{"kind":"exit","span":{"start":[5,10],"end":[5,25],"bytes":[207,222]},"id":"can://slim/typescript/src/controllers.ts/Controller/@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Controller/@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:16","kind":"fallthrough"},{"src":"5:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:16"}],"ddg":[{"src":"5:16","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:3","kind":"fallthrough"},{"src":"5:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:3"}],"ddg":[{"src":"5:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"Get":{"id":"can://slim/typescript/src/controllers.ts/Get","kind":"function","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"name":"Get","signature":"src/controllers.Get","comments":[],"decorators":[],"parameters":[{"name":"path","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":14,"end_column":26,"id":"can://slim/typescript/src/controllers.ts/Get@formal_in:0"}],"type_parameters":[],"return_type":"MethodDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"id":"can://slim/typescript/src/controllers.ts/Get@entry"},"8:3":{"kind":"statement","span":{"start":[8,3],"end":[8,26],"bytes":[274,297]},"id":"can://slim/typescript/src/controllers.ts/Get@8:3"},"@exit":{"kind":"exit","span":{"start":[7,1],"end":[9,2],"bytes":[226,299]},"id":"can://slim/typescript/src/controllers.ts/Get@exit"},"@formal_in:0":{"kind":"formal_in","of":"path","id":"can://slim/typescript/src/controllers.ts/Get@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Get@formal_out"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"arrow","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"name":"(anonymous)","signature":"src/controllers.Get.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@entry"},"8:16":{"kind":"statement","span":{"start":[8,16],"end":[8,25],"bytes":[287,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@8:16"},"@exit":{"kind":"exit","span":{"start":[8,10],"end":[8,25],"bytes":[281,296]},"id":"can://slim/typescript/src/controllers.ts/Get/@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Get/@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:16","kind":"fallthrough"},{"src":"8:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:16"}],"ddg":[{"src":"8:16","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:3","kind":"fallthrough"},{"src":"8:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:3"}],"ddg":[{"src":"8:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"Param":{"id":"can://slim/typescript/src/controllers.ts/Param","kind":"function","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"name":"Param","signature":"src/controllers.Param","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":10,"end_line":10,"start_column":16,"end_column":28,"id":"can://slim/typescript/src/controllers.ts/Param@formal_in:0"}],"type_parameters":[],"return_type":"ParameterDecorator","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"id":"can://slim/typescript/src/controllers.ts/Param@entry"},"11:3":{"kind":"statement","span":{"start":[11,3],"end":[11,26],"bytes":[353,376]},"id":"can://slim/typescript/src/controllers.ts/Param@11:3"},"@exit":{"kind":"exit","span":{"start":[10,1],"end":[12,2],"bytes":[300,378]},"id":"can://slim/typescript/src/controllers.ts/Param@exit"},"@formal_in:0":{"kind":"formal_in","of":"name","id":"can://slim/typescript/src/controllers.ts/Param@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Param@formal_out"}},"callables":{"":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"arrow","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"name":"(anonymous)","signature":"src/controllers.Param.","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"undefined","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@entry"},"11:16":{"kind":"statement","span":{"start":[11,16],"end":[11,25],"bytes":[366,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@11:16"},"@exit":{"kind":"exit","span":{"start":[11,10],"end":[11,25],"bytes":[360,375]},"id":"can://slim/typescript/src/controllers.ts/Param/@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/controllers.ts/Param/@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"11:16","kind":"fallthrough"},{"src":"11:16","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"11:16"}],"ddg":[{"src":"11:16","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"11:3","kind":"fallthrough"},{"src":"11:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"11:3"}],"ddg":[{"src":"11:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d42b8f615d51575e3436409b9fce70862182b6071da40471b4be9b95f7c9ee4c"},"src/index.ts":{"id":"can://slim/typescript/src/index.ts","kind":"module","span":{"start":[1,1],"end":[26,1],"bytes":[0,742]},"source":"import { UserController } from \"./controllers\";\nimport { Robot, Role, User } from \"./models\";\nimport { UserService, announce } from \"./services\";\nimport { StringUtil } from \"./util\";\n\nexport function main(): void {\n const service = new UserService(100);\n service.create(\"Ada\", Role.Admin);\n service.createGuest();\n\n const controller = new UserController(service);\n controller.list();\n controller.show(\"42\");\n\n // interface-typed dispatch — RTA should expand announce -> {User,Robot}.describe\n announce(new User(1, \"Ada\", Role.Admin));\n announce(new Robot(\"r2d2\"));\n\n const slug = StringUtil.repeat(\"hello world\", 2);\n const builder = new StringUtil.Builder();\n builder.add(\"a\").add(\"b\").build();\n console.log(slug);\n}\n\nmain();\n","imports":[{"module":"./controllers","name":"UserController","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":48,"resolved_module":"src/controllers.ts"},{"module":"./models","name":"Robot","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":2,"end_line":2,"start_column":1,"end_column":46,"resolved_module":"src/models.ts"},{"module":"./services","name":"UserService","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./services","name":"announce","is_type_only":false,"import_kind":"named","start_line":3,"end_line":3,"start_column":1,"end_column":52,"resolved_module":"src/services.ts"},{"module":"./util","name":"StringUtil","is_type_only":false,"import_kind":"named","start_line":4,"end_line":4,"start_column":1,"end_column":37,"resolved_module":"src/util.ts"}],"exports":[],"comments":[],"types":{},"functions":{"main":{"id":"can://slim/typescript/src/index.ts/main","kind":"function","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"name":"main","signature":"src/index.main","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"void","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"7:19":{"kind":"call","span":{"start":[7,19],"end":[7,39],"bytes":[233,253]},"callee":"can://slim/typescript/src/services.ts/UserService/constructor","method_name":"UserService","argument_types":["100"],"type_arguments":[],"return_type":"UserService","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@7:19"},"8:3":{"kind":"call","span":{"start":[8,3],"end":[8,36],"bytes":[257,290]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"service","receiver_type":"UserService","argument_types":["\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@8:3"},"9:3":{"kind":"call","span":{"start":[9,3],"end":[9,24],"bytes":[294,315]},"callee":"can://slim/typescript/src/services.ts/UserService/createGuest","method_name":"createGuest","receiver_expr":"service","receiver_type":"UserService","argument_types":[],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@9:3"},"11:22":{"kind":"call","span":{"start":[11,22],"end":[11,49],"bytes":[339,366]},"callee":"can://slim/typescript/src/controllers.ts/UserController/constructor","method_name":"UserController","argument_types":["UserService"],"type_arguments":[],"return_type":"UserController","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@11:22"},"12:3":{"kind":"call","span":{"start":[12,3],"end":[12,20],"bytes":[370,387]},"callee":"can://slim/typescript/src/controllers.ts/UserController/list","method_name":"list","receiver_expr":"controller","receiver_type":"UserController","argument_types":[],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@12:3"},"13:3":{"kind":"call","span":{"start":[13,3],"end":[13,24],"bytes":[391,412]},"callee":"can://slim/typescript/src/controllers.ts/UserController/show","method_name":"show","receiver_expr":"controller","receiver_type":"UserController","argument_types":["\"42\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@13:3"},"16:3":{"kind":"call","span":{"start":[16,3],"end":[16,43],"bytes":[503,543]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["User"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:3"},"16:12":{"kind":"call","span":{"start":[16,12],"end":[16,42],"bytes":[512,542]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["1","\"Ada\"","Role.Admin"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@16:12"},"17:3":{"kind":"call","span":{"start":[17,3],"end":[17,30],"bytes":[547,574]},"callee":"can://slim/typescript/src/services.ts/announce","method_name":"announce","argument_types":["Robot"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:3"},"17:12":{"kind":"call","span":{"start":[17,12],"end":[17,29],"bytes":[556,573]},"callee":"can://slim/typescript/src/models.ts/Robot/constructor","method_name":"Robot","argument_types":["\"r2d2\""],"type_arguments":[],"return_type":"Robot","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@17:12"},"19:16":{"kind":"call","span":{"start":[19,16],"end":[19,51],"bytes":[592,627]},"callee":"can://slim/typescript/src/util.ts/StringUtil/repeat","method_name":"repeat","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":["\"hello world\"","2"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@19:16"},"20:19":{"kind":"call","span":{"start":[20,19],"end":[20,43],"bytes":[647,671]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","method_name":"Builder","receiver_expr":"StringUtil","receiver_type":"typeof StringUtil","argument_types":[],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@20:19"},"21:3":{"kind":"call","span":{"start":[21,3],"end":[21,36],"bytes":[675,708]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","method_name":"build","receiver_expr":"builder.add(\"a\").add(\"b\")","receiver_type":"StringUtil.Builder","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3"},"21:3/2":{"kind":"call","span":{"start":[21,3],"end":[21,28],"bytes":[675,700]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder.add(\"a\")","receiver_type":"StringUtil.Builder","argument_types":["\"b\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/2"},"21:3/3":{"kind":"call","span":{"start":[21,3],"end":[21,19],"bytes":[675,691]},"callee":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","method_name":"add","receiver_expr":"builder","receiver_type":"StringUtil.Builder","argument_types":["\"a\""],"type_arguments":[],"return_type":"StringUtil.Builder","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@21:3/3"},"22:3":{"kind":"call","span":{"start":[22,3],"end":[22,20],"bytes":[712,729]},"callee":"can://slim/@external/(builtin)/log","method_name":"log","receiver_expr":"console","receiver_type":"Console","argument_types":["string"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/index.ts/main@22:3"},"@entry":{"kind":"entry","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"id":"can://slim/typescript/src/index.ts/main@entry"},"7:3":{"kind":"statement","span":{"start":[7,3],"end":[7,40],"bytes":[217,254]},"id":"can://slim/typescript/src/index.ts/main@7:3"},"11:3":{"kind":"statement","span":{"start":[11,3],"end":[11,50],"bytes":[320,367]},"id":"can://slim/typescript/src/index.ts/main@11:3"},"19:3":{"kind":"statement","span":{"start":[19,3],"end":[19,52],"bytes":[579,628]},"id":"can://slim/typescript/src/index.ts/main@19:3"},"20:3":{"kind":"statement","span":{"start":[20,3],"end":[20,44],"bytes":[631,672]},"id":"can://slim/typescript/src/index.ts/main@20:3"},"@exit":{"kind":"exit","span":{"start":[6,1],"end":[23,2],"bytes":[184,732]},"id":"can://slim/typescript/src/index.ts/main@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/index.ts/main@formal_out"},"11:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"11:3","id":"can://slim/typescript/src/index.ts/main@11:3/actual_out"},"12:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"12:3","id":"can://slim/typescript/src/index.ts/main@12:3/actual_out"},"13:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"13:3","id":"can://slim/typescript/src/index.ts/main@13:3/actual_out"},"7:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"7:3","id":"can://slim/typescript/src/index.ts/main@7:3/actual_in:0"},"8:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"8:3","id":"can://slim/typescript/src/index.ts/main@8:3/actual_in:0"},"8:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"8:3","id":"can://slim/typescript/src/index.ts/main@8:3/actual_out"},"8:3/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"8:3","id":"can://slim/typescript/src/index.ts/main@8:3/actual_in:1"},"11:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"11:3","id":"can://slim/typescript/src/index.ts/main@11:3/actual_in:0"},"13:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"13:3","id":"can://slim/typescript/src/index.ts/main@13:3/actual_in:0"},"16:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"16:3","id":"can://slim/typescript/src/index.ts/main@16:3/actual_in:0"},"16:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"16:3","id":"can://slim/typescript/src/index.ts/main@16:3/actual_out"},"16:3/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"16:3","id":"can://slim/typescript/src/index.ts/main@16:3/actual_in:1"},"16:3/actual_in:2":{"kind":"actual_in","of":"arg2","parent":"16:3","id":"can://slim/typescript/src/index.ts/main@16:3/actual_in:2"},"17:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"17:3","id":"can://slim/typescript/src/index.ts/main@17:3/actual_in:0"},"17:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"17:3","id":"can://slim/typescript/src/index.ts/main@17:3/actual_out"},"19:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"19:3","id":"can://slim/typescript/src/index.ts/main@19:3/actual_in:0"},"19:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"19:3","id":"can://slim/typescript/src/index.ts/main@19:3/actual_out"},"19:3/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"19:3","id":"can://slim/typescript/src/index.ts/main@19:3/actual_in:1"},"21:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"21:3","id":"can://slim/typescript/src/index.ts/main@21:3/actual_in:0"},"22:3/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"22:3","id":"can://slim/typescript/src/index.ts/main@22:3/actual_in:0"},"22:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"22:3","id":"can://slim/typescript/src/index.ts/main@22:3/actual_out"},"7:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"7:3","id":"can://slim/typescript/src/index.ts/main@7:3/actual_out"},"9:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"9:3","id":"can://slim/typescript/src/index.ts/main@9:3/actual_out"},"21:3/actual_out":{"kind":"actual_out","of":"$ret","parent":"21:3","id":"can://slim/typescript/src/index.ts/main@21:3/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"7:3","kind":"fallthrough"},{"src":"11:3","dst":"@exit","kind":"exception"},{"src":"11:3","dst":"12:3","kind":"fallthrough"},{"src":"12:3","dst":"@exit","kind":"exception"},{"src":"12:3","dst":"13:3","kind":"fallthrough"},{"src":"13:3","dst":"@exit","kind":"exception"},{"src":"13:3","dst":"16:3","kind":"fallthrough"},{"src":"16:3","dst":"@exit","kind":"exception"},{"src":"16:3","dst":"17:3","kind":"fallthrough"},{"src":"17:3","dst":"@exit","kind":"exception"},{"src":"17:3","dst":"19:3","kind":"fallthrough"},{"src":"19:3","dst":"@exit","kind":"exception"},{"src":"19:3","dst":"20:3","kind":"fallthrough"},{"src":"20:3","dst":"@exit","kind":"exception"},{"src":"20:3","dst":"21:3","kind":"fallthrough"},{"src":"21:3","dst":"@exit","kind":"exception"},{"src":"21:3","dst":"22:3","kind":"fallthrough"},{"src":"22:3","dst":"@exit","kind":"exception"},{"src":"22:3","dst":"@exit","kind":"fallthrough"},{"src":"7:3","dst":"@exit","kind":"exception"},{"src":"7:3","dst":"8:3","kind":"fallthrough"},{"src":"8:3","dst":"@exit","kind":"exception"},{"src":"8:3","dst":"9:3","kind":"fallthrough"},{"src":"9:3","dst":"@exit","kind":"exception"},{"src":"9:3","dst":"11:3","kind":"fallthrough"}],"cdg":[{"src":"@entry","dst":"7:3"},{"src":"11:3","dst":"12:3"},{"src":"12:3","dst":"13:3"},{"src":"13:3","dst":"16:3"},{"src":"16:3","dst":"17:3"},{"src":"17:3","dst":"19:3"},{"src":"19:3","dst":"20:3"},{"src":"20:3","dst":"21:3"},{"src":"21:3","dst":"22:3"},{"src":"7:3","dst":"8:3"},{"src":"8:3","dst":"9:3"},{"src":"9:3","dst":"11:3"}],"ddg":[{"src":"@entry","dst":"13:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"8:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"9:3","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"11:3","dst":"12:3","var":"controller.list","prov":["reaching-defs"]},{"src":"11:3","dst":"13:3","var":"controller.show","prov":["reaching-defs"]},{"src":"11:3/actual_out","dst":"11:3","var":"$ret","prov":["reaching-defs"]},{"src":"12:3/actual_out","dst":"12:3","var":"$ret","prov":["reaching-defs"]},{"src":"13:3/actual_out","dst":"13:3","var":"$ret","prov":["reaching-defs"]},{"src":"16:3/actual_out","dst":"16:3","var":"$ret","prov":["reaching-defs"]},{"src":"17:3/actual_out","dst":"17:3","var":"$ret","prov":["reaching-defs"]},{"src":"19:3","dst":"22:3","var":"slug","prov":["reaching-defs"]},{"src":"19:3/actual_out","dst":"19:3","var":"$ret","prov":["reaching-defs"]},{"src":"20:3","dst":"21:3","var":"builder.add","prov":["reaching-defs"]},{"src":"21:3/actual_out","dst":"21:3","var":"$ret","prov":["reaching-defs"]},{"src":"7:3","dst":"11:3","var":"service","prov":["reaching-defs"]},{"src":"7:3","dst":"11:3/actual_in:0","var":"service","prov":["reaching-defs"]},{"src":"7:3","dst":"8:3","var":"service.create","prov":["reaching-defs"]},{"src":"7:3","dst":"9:3","var":"service.createGuest","prov":["reaching-defs"]},{"src":"7:3/actual_out","dst":"7:3","var":"$ret","prov":["reaching-defs"]},{"src":"8:3/actual_out","dst":"8:3","var":"$ret","prov":["reaching-defs"]},{"src":"9:3/actual_out","dst":"9:3","var":"$ret","prov":["reaching-defs"]}],"summary":[{"src":"13:3","dst":"13:3","var":"src/services.nextId"},{"src":"13:3/actual_in:0","dst":"13:3/actual_out"},{"src":"16:3/actual_in:0","dst":"16:3/actual_out"},{"src":"17:3/actual_in:0","dst":"17:3/actual_out"},{"src":"19:3/actual_in:0","dst":"19:3/actual_out"},{"src":"19:3/actual_in:1","dst":"19:3/actual_out"},{"src":"22:3/actual_in:0","dst":"22:3/actual_out"},{"src":"8:3","dst":"8:3","var":"src/services.nextId"},{"src":"8:3/actual_in:0","dst":"8:3/actual_out"},{"src":"8:3/actual_in:1","dst":"8:3/actual_out"},{"src":"9:3","dst":"9:3","var":"src/services.nextId"}]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"6de6f6ff5a01a5c7c750a93d5e10bae7b15817f386421f45c7527cfb7259d9b3"},"src/models.ts":{"id":"can://slim/typescript/src/models.ts","kind":"module","span":{"start":[1,1],"end":[65,1],"bytes":[0,1237]},"source":"/** Domain models for the sample app. */\n\nexport interface Identifiable {\n readonly id: T;\n}\n\nexport interface Named {\n name: string;\n describe(): string;\n}\n\nexport type UserId = string | number;\n\nexport enum Role {\n Admin = \"admin\",\n Member = \"member\",\n Guest = \"guest\",\n}\n\nexport const enum Flag {\n None = 0,\n Active = 1,\n}\n\n/** A user of the system. */\nexport abstract class Entity implements Identifiable {\n constructor(public readonly id: ID) {}\n abstract describe(): string;\n}\n\nexport class User extends Entity implements Named {\n private loginCount = 0;\n static instances = 0;\n\n constructor(\n id: UserId,\n public name: string,\n private role: Role = Role.Member,\n ) {\n super(id);\n User.instances++;\n }\n\n get isAdmin(): boolean {\n return this.role === Role.Admin;\n }\n\n describe(): string {\n return `${this.name} (${this.role})`;\n }\n\n async recordLogin(): Promise {\n this.loginCount += 1;\n return this.loginCount;\n }\n}\n\n/** A second, unrelated implementer of Named — drives RTA subtype expansion. */\nexport class Robot implements Named {\n constructor(public name: string) {}\n describe(): string {\n return `robot:${this.name}`;\n }\n}\n","imports":[],"exports":[],"comments":[{"content":"/** Domain models for the sample app. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41},{"content":"/** A user of the system. */","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29},{"content":"/** A second, unrelated implementer of Named — drives RTA subtype expansion. */","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"types":{"Entity":{"id":"can://slim/typescript/src/models.ts/Entity","kind":"class","span":{"start":[26,1],"end":[29,2],"bytes":[376,521]},"name":"Entity","signature":"src/models.Entity","comments":[{"content":"A user of the system.","is_docstring":true,"start_line":25,"end_line":25,"start_column":1,"end_column":29}],"decorators":[],"base_classes":["src/models.Identifiable"],"implements_types":["src/models.Identifiable"],"type_parameters":[{"name":"ID","default":"string"}],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Entity/describe","kind":"method","span":{"start":[28,3],"end":[28,31],"bytes":[491,519]},"name":"describe","signature":"src/models.Entity.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":true,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[{"parameters":[],"return_type":"string","type_parameters":[],"start_line":28,"end_line":28}],"body":{},"entrypoints":[],"is_entrypoint":false},"constructor":{"id":"can://slim/typescript/src/models.ts/Entity/constructor","kind":"constructor","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"name":"constructor","signature":"src/models.Entity.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"ID","is_optional":false,"is_rest":false,"is_readonly":true,"accessibility":"public","decorators":[],"start_line":27,"end_line":27,"start_column":15,"end_column":37,"id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"id":"can://slim/typescript/src/models.ts/Entity/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[27,3],"end":[27,41],"bytes":[450,488]},"id":"can://slim/typescript/src/models.ts/Entity/constructor@exit"},"@formal_in:0":{"kind":"formal_in","of":"id","id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/Entity/constructor@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[],"summary":[]}},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Entity/id","kind":"field","name":"id","type":"ID","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"is_abstract":true,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Identifiable"],"entrypoints":[],"is_entrypoint":false},"User":{"id":"can://slim/typescript/src/models.ts/User","kind":"class","span":{"start":[31,1],"end":[56,2],"bytes":[523,1015]},"name":"User","signature":"src/models.User","comments":[],"decorators":[],"base_classes":["src/models.Entity","src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/User/describe","kind":"method","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"name":"describe","signature":"src/models.User.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"id":"can://slim/typescript/src/models.ts/User/describe@entry"},"49:5":{"kind":"statement","span":{"start":[49,5],"end":[49,42],"bytes":[872,909]},"id":"can://slim/typescript/src/models.ts/User/describe@49:5"},"@exit":{"kind":"exit","span":{"start":[48,3],"end":[50,4],"bytes":[847,913]},"id":"can://slim/typescript/src/models.ts/User/describe@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/User/describe@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"49:5","kind":"fallthrough"},{"src":"49:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"49:5"}],"ddg":[{"src":"@entry","dst":"49:5","var":"this.name","prov":["reaching-defs"]},{"src":"@entry","dst":"49:5","var":"this.role","prov":["reaching-defs"]},{"src":"49:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"recordLogin":{"id":"can://slim/typescript/src/models.ts/User/recordLogin","kind":"method","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"name":"recordLogin","signature":"src/models.User.recordLogin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@entry"},"53:5":{"kind":"statement","span":{"start":[53,5],"end":[53,26],"bytes":[960,981]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@53:5"},"54:5":{"kind":"statement","span":{"start":[54,5],"end":[54,28],"bytes":[986,1009]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@54:5"},"@exit":{"kind":"exit","span":{"start":[52,3],"end":[55,4],"bytes":[917,1013]},"id":"can://slim/typescript/src/models.ts/User/recordLogin@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/User/recordLogin@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"53:5","kind":"fallthrough"},{"src":"53:5","dst":"54:5","kind":"fallthrough"},{"src":"54:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"53:5"},{"src":"@entry","dst":"54:5"}],"ddg":[{"src":"@entry","dst":"53:5","var":"this.loginCount","prov":["reaching-defs"]},{"src":"@entry","dst":"54:5","var":"this.loginCount","prov":["reaching-defs"]},{"src":"53:5","dst":"54:5","var":"this.loginCount","prov":["reaching-defs"]},{"src":"54:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"constructor":{"id":"can://slim/typescript/src/models.ts/User/constructor","kind":"constructor","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"name":"constructor","signature":"src/models.User.constructor","comments":[],"decorators":[],"parameters":[{"name":"id","type":"UserId","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":36,"end_line":36,"start_column":5,"end_column":15,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0"},{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":37,"end_line":37,"start_column":5,"end_column":24,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"accessibility":"private","decorators":[],"start_line":38,"end_line":38,"start_column":5,"end_column":37,"id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"40:5":{"kind":"call","span":{"start":[40,5],"end":[40,14],"bytes":[738,747]},"callee":"can://slim/typescript/src/models.ts/Entity/constructor","method_name":"super","argument_types":["UserId"],"type_arguments":[],"return_type":"void","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/models.ts/User/constructor@40:5"},"@entry":{"kind":"entry","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"id":"can://slim/typescript/src/models.ts/User/constructor@entry"},"41:5":{"kind":"statement","span":{"start":[41,5],"end":[41,22],"bytes":[753,770]},"id":"can://slim/typescript/src/models.ts/User/constructor@41:5"},"@exit":{"kind":"exit","span":{"start":[35,3],"end":[42,4],"bytes":[636,774]},"id":"can://slim/typescript/src/models.ts/User/constructor@exit"},"@formal_in:0":{"kind":"formal_in","of":"id","id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0"},"@formal_in:1":{"kind":"formal_in","of":"name","id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1"},"@formal_in:2":{"kind":"formal_in","of":"role","id":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/User/constructor@formal_out"},"40:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"40:5","id":"can://slim/typescript/src/models.ts/User/constructor@40:5/actual_out"},"40:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"40:5","id":"can://slim/typescript/src/models.ts/User/constructor@40:5/actual_in:0"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"40:5","kind":"fallthrough"},{"src":"40:5","dst":"@exit","kind":"exception"},{"src":"40:5","dst":"41:5","kind":"fallthrough"},{"src":"41:5","dst":"@exit","kind":"fallthrough"}],"cdg":[{"src":"@entry","dst":"40:5"},{"src":"40:5","dst":"41:5"}],"ddg":[{"src":"@entry","dst":"40:5","var":"id","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"40:5","var":"id","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"40:5/actual_in:0","var":"id","prov":["reaching-defs"]},{"src":"40:5/actual_out","dst":"40:5","var":"$ret","prov":["reaching-defs"]}],"summary":[]},"isAdmin#get":{"id":"can://slim/typescript/src/models.ts/User/isAdmin","kind":"getter","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"name":"isAdmin","signature":"src/models.User.isAdmin","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"boolean","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"accessor_kind":"getter","overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@entry"},"45:5":{"kind":"statement","span":{"start":[45,5],"end":[45,37],"bytes":[807,839]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@45:5"},"@exit":{"kind":"exit","span":{"start":[44,3],"end":[46,4],"bytes":[778,843]},"id":"can://slim/typescript/src/models.ts/User/isAdmin@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/User/isAdmin@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"45:5","kind":"fallthrough"},{"src":"45:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"45:5"}],"ddg":[{"src":"@entry","dst":"45:5","var":"this.role","prov":["reaching-defs"]},{"src":"45:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"fields":{"loginCount":{"id":"can://slim/typescript/src/models.ts/User/loginCount","kind":"field","span":{"start":[32,3],"end":[32,26],"bytes":[585,608]},"name":"loginCount","type":"number","comments":[],"decorators":[],"initializer":"0","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"instances":{"id":"can://slim/typescript/src/models.ts/User/instances","kind":"field","span":{"start":[33,3],"end":[33,24],"bytes":[611,632]},"name":"instances","type":"number","comments":[],"decorators":[],"initializer":"0","is_static":true,"is_readonly":false,"is_optional":false,"is_abstract":false},"name":{"id":"can://slim/typescript/src/models.ts/User/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"role":{"id":"can://slim/typescript/src/models.ts/User/role","kind":"field","name":"role","type":"Role","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":false,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"extends_ids":["can://slim/typescript/src/models.ts/Entity"],"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Robot":{"id":"can://slim/typescript/src/models.ts/Robot","kind":"class","span":{"start":[59,1],"end":[64,2],"bytes":[1099,1236]},"name":"Robot","signature":"src/models.Robot","comments":[{"content":"A second, unrelated implementer of Named — drives RTA subtype expansion.","is_docstring":true,"start_line":58,"end_line":58,"start_column":1,"end_column":80}],"decorators":[],"base_classes":["src/models.Named"],"implements_types":["src/models.Named"],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Robot/describe","kind":"method","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"name":"describe","signature":"src/models.Robot.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"id":"can://slim/typescript/src/models.ts/Robot/describe@entry"},"62:5":{"kind":"statement","span":{"start":[62,5],"end":[62,33],"bytes":[1202,1230]},"id":"can://slim/typescript/src/models.ts/Robot/describe@62:5"},"@exit":{"kind":"exit","span":{"start":[61,3],"end":[63,4],"bytes":[1177,1234]},"id":"can://slim/typescript/src/models.ts/Robot/describe@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/Robot/describe@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"62:5","kind":"fallthrough"},{"src":"62:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"62:5"}],"ddg":[{"src":"@entry","dst":"62:5","var":"this.name","prov":["reaching-defs"]},{"src":"62:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"constructor":{"id":"can://slim/typescript/src/models.ts/Robot/constructor","kind":"constructor","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"name":"constructor","signature":"src/models.Robot.constructor","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"accessibility":"public","decorators":[],"start_line":60,"end_line":60,"start_column":15,"end_column":34,"id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"id":"can://slim/typescript/src/models.ts/Robot/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[60,3],"end":[60,38],"bytes":[1139,1174]},"id":"can://slim/typescript/src/models.ts/Robot/constructor@exit"},"@formal_in:0":{"kind":"formal_in","of":"name","id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/models.ts/Robot/constructor@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[],"summary":[]}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Robot/name","kind":"field","name":"name","type":"string","comments":[],"decorators":[],"accessibility":"public","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"implements_ids":["can://slim/typescript/src/models.ts/Named"],"entrypoints":[],"is_entrypoint":false},"Identifiable":{"id":"can://slim/typescript/src/models.ts/Identifiable","kind":"interface","span":{"start":[3,1],"end":[5,2],"bytes":[42,105]},"name":"Identifiable","signature":"src/models.Identifiable","comments":[{"content":"Domain models for the sample app.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":41}],"base_classes":[],"type_parameters":[{"name":"T","default":"string"}],"callables":{},"fields":{"id":{"id":"can://slim/typescript/src/models.ts/Identifiable/id","kind":"field","span":{"start":[4,3],"end":[4,18],"bytes":[88,103]},"name":"id","type":"T","comments":[],"decorators":[],"is_static":false,"is_readonly":true,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Named":{"id":"can://slim/typescript/src/models.ts/Named","kind":"interface","span":{"start":[7,1],"end":[10,2],"bytes":[107,171]},"name":"Named","signature":"src/models.Named","comments":[],"base_classes":[],"type_parameters":[],"callables":{"describe":{"id":"can://slim/typescript/src/models.ts/Named/describe","kind":"method","span":{"start":[9,3],"end":[9,22],"bytes":[150,169]},"name":"describe","signature":"src/models.Named.describe","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"name":{"id":"can://slim/typescript/src/models.ts/Named/name","kind":"field","span":{"start":[8,3],"end":[8,16],"bytes":[134,147]},"name":"name","type":"string","comments":[],"decorators":[],"is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"call_signatures":[],"index_signatures":[],"is_exported":true,"is_ambient":false},"Role":{"id":"can://slim/typescript/src/models.ts/Role","kind":"enum","span":{"start":[14,1],"end":[18,2],"bytes":[212,291]},"name":"Role","signature":"src/models.Role","comments":[],"fields":{"Admin":{"id":"can://slim/typescript/src/models.ts/Role/Admin","kind":"field","span":{"start":[15,3],"end":[15,18],"bytes":[233,248]},"name":"Admin","value":"admin"},"Member":{"id":"can://slim/typescript/src/models.ts/Role/Member","kind":"field","span":{"start":[16,3],"end":[16,20],"bytes":[252,269]},"name":"Member","value":"member"},"Guest":{"id":"can://slim/typescript/src/models.ts/Role/Guest","kind":"field","span":{"start":[17,3],"end":[17,18],"bytes":[273,288]},"name":"Guest","value":"guest"}},"is_const":false,"is_exported":true,"is_ambient":false},"Flag":{"id":"can://slim/typescript/src/models.ts/Flag","kind":"enum","span":{"start":[20,1],"end":[23,2],"bytes":[293,345]},"name":"Flag","signature":"src/models.Flag","comments":[],"fields":{"None":{"id":"can://slim/typescript/src/models.ts/Flag/None","kind":"field","span":{"start":[21,3],"end":[21,11],"bytes":[320,328]},"name":"None","value":"0"},"Active":{"id":"can://slim/typescript/src/models.ts/Flag/Active","kind":"field","span":{"start":[22,3],"end":[22,13],"bytes":[332,342]},"name":"Active","value":"1"}},"is_const":true,"is_exported":true,"is_ambient":false},"UserId":{"id":"can://slim/typescript/src/models.ts/UserId","kind":"type_alias","span":{"start":[12,1],"end":[12,38],"bytes":[173,210]},"name":"UserId","signature":"src/models.UserId","comments":[],"aliased_type":"string | number","type_parameters":[],"is_exported":true,"is_ambient":false}},"functions":{},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"d39ff571ccfda4b7c46923586b6b94d0e818a51be966f1ba40305650fd0ffc91"},"src/services.ts":{"id":"can://slim/typescript/src/services.ts","kind":"module","span":{"start":[1,1],"end":[48,1],"bytes":[0,1240]},"source":"import { type Named, Role, User, type UserId } from \"./models\";\n\n/** Pure helper — top-level function. */\nexport function makeGuestName(seed: number): string {\n return `guest-${seed}`;\n}\n\n/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */\nexport function announce(thing: Named): string {\n return thing.describe();\n}\n\n/** Arrow function bound to a const (function_expression-style callable). */\nexport const nextId = (n: number): UserId => n + 1;\n\nexport class UserService {\n private users: User[] = [];\n\n constructor(private readonly startId: number = 0) {}\n\n create(name: string, role: Role = Role.Member): User {\n const id = nextId(this.users.length + this.startId);\n const user = new User(id, name, role);\n this.users.push(user);\n return user;\n }\n\n createGuest(): User {\n const name = makeGuestName(this.users.length);\n return this.create(name, Role.Guest);\n }\n\n describeAll(): string[] {\n return this.users.map((u) => u.describe());\n }\n\n async loginAll(): Promise {\n let total = 0;\n for (const u of this.users) {\n total += await u.recordLogin();\n }\n return total;\n }\n}\n","imports":[{"module":"./models","name":"Named","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"Role","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"User","is_type_only":false,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"},{"module":"./models","name":"UserId","is_type_only":true,"import_kind":"named","start_line":1,"end_line":1,"start_column":1,"end_column":64,"resolved_module":"src/models.ts"}],"exports":[],"comments":[{"content":"/** Pure helper — top-level function. */","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41},{"content":"/**\n * Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\n * concrete implementer of Named (User, Robot, ...).\n */","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4},{"content":"/** Arrow function bound to a const (function_expression-style callable). */","is_docstring":true,"start_line":16,"end_line":16,"start_column":1,"end_column":77}],"types":{"UserService":{"id":"can://slim/typescript/src/services.ts/UserService","kind":"class","span":{"start":[19,1],"end":[47,2],"bytes":[558,1239]},"name":"UserService","signature":"src/services.UserService","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"create":{"id":"can://slim/typescript/src/services.ts/UserService/create","kind":"method","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"name":"create","signature":"src/services.UserService.create","comments":[],"decorators":[],"parameters":[{"name":"name","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":10,"end_column":22,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0"},{"name":"role","type":"Role","default_value":"Role.Member","is_optional":true,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":24,"end_column":48,"id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1"}],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"25:16":{"kind":"call","span":{"start":[25,16],"end":[25,56],"bytes":[744,784]},"callee":"can://slim/typescript/src/services.ts/nextId","method_name":"nextId","argument_types":["number"],"type_arguments":[],"return_type":"UserId","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@25:16"},"26:18":{"kind":"call","span":{"start":[26,18],"end":[26,42],"bytes":[803,827]},"callee":"can://slim/typescript/src/models.ts/User/constructor","method_name":"User","argument_types":["UserId","string","Role"],"type_arguments":[],"return_type":"User","is_constructor_call":true,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@26:18"},"27:5":{"kind":"call","span":{"start":[27,5],"end":[27,26],"bytes":[833,854]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["User"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/create@27:5"},"@entry":{"kind":"entry","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"id":"can://slim/typescript/src/services.ts/UserService/create@entry"},"25:5":{"kind":"statement","span":{"start":[25,5],"end":[25,57],"bytes":[733,785]},"id":"can://slim/typescript/src/services.ts/UserService/create@25:5"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,43],"bytes":[790,828]},"id":"can://slim/typescript/src/services.ts/UserService/create@26:5"},"28:5":{"kind":"statement","span":{"start":[28,5],"end":[28,17],"bytes":[860,872]},"id":"can://slim/typescript/src/services.ts/UserService/create@28:5"},"@exit":{"kind":"exit","span":{"start":[24,3],"end":[29,4],"bytes":[674,876]},"id":"can://slim/typescript/src/services.ts/UserService/create@exit"},"@formal_in:0":{"kind":"formal_in","of":"name","id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0"},"@formal_in:1":{"kind":"formal_in","of":"role","id":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/create@formal_out"},"26:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"26:5","id":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_out"},"25:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"25:5","id":"can://slim/typescript/src/services.ts/UserService/create@25:5/actual_out"},"25:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"25:5","id":"can://slim/typescript/src/services.ts/UserService/create@25:5/actual_in:0"},"26:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"26:5","id":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:0"},"26:5/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"26:5","id":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:1"},"26:5/actual_in:2":{"kind":"actual_in","of":"arg2","parent":"26:5","id":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:2"},"27:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"27:5","id":"can://slim/typescript/src/services.ts/UserService/create@27:5/actual_in:0"},"27:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"27:5","id":"can://slim/typescript/src/services.ts/UserService/create@27:5/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"25:5","kind":"fallthrough"},{"src":"25:5","dst":"@exit","kind":"exception"},{"src":"25:5","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"27:5","kind":"fallthrough"},{"src":"27:5","dst":"@exit","kind":"exception"},{"src":"27:5","dst":"28:5","kind":"fallthrough"},{"src":"28:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"25:5"},{"src":"25:5","dst":"26:5"},{"src":"26:5","dst":"27:5"},{"src":"27:5","dst":"28:5"}],"ddg":[{"src":"@entry","dst":"25:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5","var":"this.startId","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5/actual_in:0","var":"this.startId","prov":["reaching-defs"]},{"src":"@entry","dst":"25:5/actual_in:0","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"26:5","var":"name","prov":["reaching-defs"]},{"src":"@entry","dst":"26:5","var":"role","prov":["reaching-defs"]},{"src":"@entry","dst":"27:5","var":"this.users.push","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"26:5","var":"name","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"26:5/actual_in:1","var":"name","prov":["reaching-defs"]},{"src":"@formal_in:1","dst":"26:5","var":"role","prov":["reaching-defs"]},{"src":"@formal_in:1","dst":"26:5/actual_in:2","var":"role","prov":["reaching-defs"]},{"src":"25:5","dst":"26:5","var":"id","prov":["reaching-defs"]},{"src":"25:5","dst":"26:5/actual_in:0","var":"id","prov":["reaching-defs"]},{"src":"25:5/actual_out","dst":"25:5","var":"$ret","prov":["reaching-defs"]},{"src":"26:5","dst":"27:5","var":"user","prov":["reaching-defs"]},{"src":"26:5","dst":"28:5","var":"user","prov":["reaching-defs"]},{"src":"26:5/actual_out","dst":"26:5","var":"$ret","prov":["reaching-defs"]},{"src":"28:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"25:5/actual_in:0","dst":"25:5/actual_out"},{"src":"27:5/actual_in:0","dst":"27:5/actual_out"}]},"createGuest":{"id":"can://slim/typescript/src/services.ts/UserService/createGuest","kind":"method","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"name":"createGuest","signature":"src/services.UserService.createGuest","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"User","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"32:18":{"kind":"call","span":{"start":[32,18],"end":[32,50],"bytes":[919,951]},"callee":"can://slim/typescript/src/services.ts/makeGuestName","method_name":"makeGuestName","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:18"},"33:12":{"kind":"call","span":{"start":[33,12],"end":[33,41],"bytes":[964,993]},"callee":"can://slim/typescript/src/services.ts/UserService/create","method_name":"create","receiver_expr":"this","receiver_type":"this","argument_types":["string","Role.Guest"],"type_arguments":[],"return_type":"User","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:12"},"@entry":{"kind":"entry","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@entry"},"32:5":{"kind":"statement","span":{"start":[32,5],"end":[32,51],"bytes":[906,952]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5"},"33:5":{"kind":"statement","span":{"start":[33,5],"end":[33,42],"bytes":[957,994]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5"},"@exit":{"kind":"exit","span":{"start":[31,3],"end":[34,4],"bytes":[880,998]},"id":"can://slim/typescript/src/services.ts/UserService/createGuest@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/createGuest@formal_out"},"32:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"32:5","id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5/actual_out"},"33:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"33:5","id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_out"},"32:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"32:5","id":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5/actual_in:0"},"33:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"33:5","id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_in:0"},"33:5/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"33:5","id":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_in:1"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"32:5","kind":"fallthrough"},{"src":"32:5","dst":"@exit","kind":"exception"},{"src":"32:5","dst":"33:5","kind":"fallthrough"},{"src":"33:5","dst":"@exit","kind":"exception"},{"src":"33:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"32:5"},{"src":"32:5","dst":"33:5"}],"ddg":[{"src":"@entry","dst":"32:5","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"32:5/actual_in:0","var":"this.users.length","prov":["reaching-defs"]},{"src":"@entry","dst":"33:5","var":"src/services.nextId","prov":["reaching-defs"]},{"src":"@entry","dst":"33:5","var":"this.create","prov":["reaching-defs"]},{"src":"32:5","dst":"33:5","var":"name","prov":["reaching-defs"]},{"src":"32:5","dst":"33:5/actual_in:0","var":"name","prov":["reaching-defs"]},{"src":"32:5/actual_out","dst":"32:5","var":"$ret","prov":["reaching-defs"]},{"src":"33:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]},{"src":"33:5/actual_out","dst":"33:5","var":"$ret","prov":["reaching-defs"]}],"summary":[{"src":"32:5/actual_in:0","dst":"32:5/actual_out"},{"src":"33:5","dst":"33:5","var":"src/services.nextId"},{"src":"33:5/actual_in:0","dst":"33:5/actual_out"},{"src":"33:5/actual_in:1","dst":"33:5/actual_out"}]},"describeAll":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll","kind":"method","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"name":"describeAll","signature":"src/services.UserService.describeAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string[]","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:12":{"kind":"call","span":{"start":[37,12],"end":[37,47],"bytes":[1039,1074]},"callee":"can://slim/@external/(builtin)/map","method_name":"map","receiver_expr":"this.users","receiver_type":"User[]","argument_types":["(u: User) => string"],"type_arguments":[],"return_type":"string[]","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:12"},"@entry":{"kind":"entry","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@entry"},"37:5":{"kind":"statement","span":{"start":[37,5],"end":[37,48],"bytes":[1032,1075]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:5"},"@exit":{"kind":"exit","span":{"start":[36,3],"end":[38,4],"bytes":[1002,1079]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/describeAll@formal_out"},"37:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"37:5","id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:5/actual_in:0"},"37:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"37:5","id":"can://slim/typescript/src/services.ts/UserService/describeAll@37:5/actual_out"}},"callables":{"":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"arrow","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"name":"(anonymous)","signature":"src/services.UserService.describeAll.","comments":[],"decorators":[],"parameters":[{"name":"u","type":"User","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":37,"end_line":37,"start_column":28,"end_column":29,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"37:34":{"kind":"call","span":{"start":[37,34],"end":[37,46],"bytes":[1061,1073]},"callee":"can://slim/typescript/src/models.ts/User/describe","method_name":"describe","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34"},"@entry":{"kind":"entry","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@entry"},"@exit":{"kind":"exit","span":{"start":[37,27],"end":[37,46],"bytes":[1054,1073]},"id":"can://slim/typescript/src/services.ts/UserService/describeAll/@exit"},"@formal_in:0":{"kind":"formal_in","of":"u","id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/describeAll/@formal_out"},"37:34/actual_out":{"kind":"actual_out","of":"$ret","parent":"37:34","id":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"37:34","kind":"fallthrough"},{"src":"37:34","dst":"@exit","kind":"exception"},{"src":"37:34","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"37:34"}],"ddg":[{"src":"@entry","dst":"37:34","var":"u.describe","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"37:34","var":"u.describe","prov":["reaching-defs"]},{"src":"37:34","dst":"@formal_out","var":"return","prov":["reaching-defs"]},{"src":"37:34/actual_out","dst":"37:34","var":"$ret","prov":["reaching-defs"]}],"summary":[]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"37:5","kind":"fallthrough"},{"src":"37:5","dst":"@exit","kind":"exception"},{"src":"37:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"37:5"}],"ddg":[{"src":"@entry","dst":"37:5","var":"this.users.map","prov":["reaching-defs"]},{"src":"37:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"37:5/actual_in:0","dst":"37:5/actual_out"}]},"loginAll":{"id":"can://slim/typescript/src/services.ts/UserService/loginAll","kind":"method","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"name":"loginAll","signature":"src/services.UserService.loginAll","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"Promise","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":true,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"43:22":{"kind":"call","span":{"start":[43,22],"end":[43,37],"bytes":[1193,1208]},"callee":"can://slim/typescript/src/models.ts/User/recordLogin","method_name":"recordLogin","receiver_expr":"u","receiver_type":"User","argument_types":[],"type_arguments":[],"return_type":"Promise","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:22"},"@entry":{"kind":"entry","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@entry"},"41:5":{"kind":"statement","span":{"start":[41,5],"end":[41,19],"bytes":[1123,1137]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@41:5"},"42:5":{"kind":"statement","span":{"start":[42,5],"end":[44,6],"bytes":[1142,1215]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@42:5"},"43:7":{"kind":"statement","span":{"start":[43,7],"end":[43,38],"bytes":[1178,1209]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:7"},"45:5":{"kind":"statement","span":{"start":[45,5],"end":[45,18],"bytes":[1220,1233]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@45:5"},"@exit":{"kind":"exit","span":{"start":[40,3],"end":[46,4],"bytes":[1083,1237]},"id":"can://slim/typescript/src/services.ts/UserService/loginAll@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/loginAll@formal_out"},"43:7/actual_out":{"kind":"actual_out","of":"$ret","parent":"43:7","id":"can://slim/typescript/src/services.ts/UserService/loginAll@43:7/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"41:5","kind":"fallthrough"},{"src":"41:5","dst":"42:5","kind":"fallthrough"},{"src":"42:5","dst":"43:7","kind":"true"},{"src":"42:5","dst":"45:5","kind":"false"},{"src":"43:7","dst":"@exit","kind":"exception"},{"src":"43:7","dst":"42:5","kind":"loop_back"},{"src":"45:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"41:5"},{"src":"@entry","dst":"42:5"},{"src":"42:5","dst":"43:7"},{"src":"42:5","dst":"45:5"},{"src":"43:7","dst":"42:5"}],"ddg":[{"src":"@entry","dst":"42:5","var":"this.users","prov":["reaching-defs"]},{"src":"41:5","dst":"43:7","var":"total","prov":["reaching-defs"]},{"src":"41:5","dst":"45:5","var":"total","prov":["reaching-defs"]},{"src":"42:5","dst":"43:7","var":"u.recordLogin","prov":["reaching-defs"]},{"src":"43:7","dst":"43:7","var":"total","prov":["reaching-defs"]},{"src":"43:7","dst":"45:5","var":"total","prov":["reaching-defs"]},{"src":"43:7/actual_out","dst":"43:7","var":"$ret","prov":["reaching-defs"]},{"src":"45:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"constructor":{"id":"can://slim/typescript/src/services.ts/UserService/constructor","kind":"constructor","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"name":"constructor","signature":"src/services.UserService.constructor","comments":[],"decorators":[],"parameters":[{"name":"startId","type":"number","default_value":"0","is_optional":true,"is_rest":false,"is_readonly":true,"accessibility":"private","decorators":[],"start_line":22,"end_line":22,"start_column":15,"end_column":51,"id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0"}],"type_parameters":[],"cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"id":"can://slim/typescript/src/services.ts/UserService/constructor@entry"},"@exit":{"kind":"exit","span":{"start":[22,3],"end":[22,55],"bytes":[618,670]},"id":"can://slim/typescript/src/services.ts/UserService/constructor@exit"},"@formal_in:0":{"kind":"formal_in","of":"startId","id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/UserService/constructor@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"@exit","kind":"fallthrough"}],"cdg":[],"ddg":[],"summary":[]}},"fields":{"users":{"id":"can://slim/typescript/src/services.ts/UserService/users","kind":"field","span":{"start":[20,3],"end":[20,30],"bytes":[587,614]},"name":"users","type":"User[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false},"startId":{"id":"can://slim/typescript/src/services.ts/UserService/startId","kind":"field","name":"startId","type":"number","comments":[],"decorators":[],"accessibility":"private","is_static":false,"is_readonly":true,"is_optional":true,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"makeGuestName":{"id":"can://slim/typescript/src/services.ts/makeGuestName","kind":"function","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"name":"makeGuestName","signature":"src/services.makeGuestName","comments":[{"content":"Pure helper — top-level function.","is_docstring":true,"start_line":3,"end_line":3,"start_column":1,"end_column":41}],"decorators":[],"parameters":[{"name":"seed","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":4,"end_line":4,"start_column":31,"end_column":43,"id":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"id":"can://slim/typescript/src/services.ts/makeGuestName@entry"},"5:3":{"kind":"statement","span":{"start":[5,3],"end":[5,26],"bytes":[164,187]},"id":"can://slim/typescript/src/services.ts/makeGuestName@5:3"},"@exit":{"kind":"exit","span":{"start":[4,1],"end":[6,2],"bytes":[108,189]},"id":"can://slim/typescript/src/services.ts/makeGuestName@exit"},"@formal_in:0":{"kind":"formal_in","of":"seed","id":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/makeGuestName@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"5:3","kind":"fallthrough"},{"src":"5:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"5:3"}],"ddg":[{"src":"@entry","dst":"5:3","var":"seed","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"5:3","var":"seed","prov":["reaching-defs"]},{"src":"5:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"announce":{"id":"can://slim/typescript/src/services.ts/announce","kind":"function","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"name":"announce","signature":"src/services.announce","comments":[{"content":"Calls describe() on an interface-typed receiver. Under RTA this expands to every instantiated\nconcrete implementer of Named (User, Robot, ...).","is_docstring":true,"start_line":8,"end_line":11,"start_column":1,"end_column":4}],"decorators":[],"parameters":[{"name":"thing","type":"Named","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":12,"end_line":12,"start_column":26,"end_column":38,"id":"can://slim/typescript/src/services.ts/announce@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"13:10":{"kind":"call","span":{"start":[13,10],"end":[13,26],"bytes":[407,423]},"callee":"can://slim/typescript/src/models.ts/Named/describe","method_name":"describe","receiver_expr":"thing","receiver_type":"Named","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/services.ts/announce@13:10"},"@entry":{"kind":"entry","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"id":"can://slim/typescript/src/services.ts/announce@entry"},"13:3":{"kind":"statement","span":{"start":[13,3],"end":[13,27],"bytes":[400,424]},"id":"can://slim/typescript/src/services.ts/announce@13:3"},"@exit":{"kind":"exit","span":{"start":[12,1],"end":[14,2],"bytes":[349,426]},"id":"can://slim/typescript/src/services.ts/announce@exit"},"@formal_in:0":{"kind":"formal_in","of":"thing","id":"can://slim/typescript/src/services.ts/announce@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/announce@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"13:3","kind":"fallthrough"},{"src":"13:3","dst":"@exit","kind":"exception"},{"src":"13:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"13:3"}],"ddg":[{"src":"@entry","dst":"13:3","var":"thing.describe","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"13:3","var":"thing.describe","prov":["reaching-defs"]},{"src":"13:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]},"nextId":{"id":"can://slim/typescript/src/services.ts/nextId","kind":"arrow","span":{"start":[17,14],"end":[17,51],"bytes":[518,555]},"name":"nextId","signature":"src/services.nextId","comments":[],"decorators":[],"parameters":[{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":17,"end_line":17,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/services.ts/nextId@formal_in:0"}],"type_parameters":[],"return_type":"UserId","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"@entry":{"kind":"entry","span":{"start":[17,23],"end":[17,51],"bytes":[527,555]},"id":"can://slim/typescript/src/services.ts/nextId@entry"},"17:46":{"kind":"statement","span":{"start":[17,46],"end":[17,51],"bytes":[550,555]},"id":"can://slim/typescript/src/services.ts/nextId@17:46"},"@exit":{"kind":"exit","span":{"start":[17,23],"end":[17,51],"bytes":[527,555]},"id":"can://slim/typescript/src/services.ts/nextId@exit"},"@formal_in:0":{"kind":"formal_in","of":"n","id":"can://slim/typescript/src/services.ts/nextId@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/services.ts/nextId@formal_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"17:46","kind":"fallthrough"},{"src":"17:46","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"17:46"}],"ddg":[{"src":"@entry","dst":"17:46","var":"n","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"17:46","var":"n","prov":["reaching-defs"]},{"src":"17:46","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"1bda3666dab48f8e686fb8ffc2143f2e422af62be46698053cfeea4184b55617"},"src/util.ts":{"id":"can://slim/typescript/src/util.ts","kind":"module","span":{"start":[1,1],"end":[35,1],"bytes":[0,949]},"source":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */\nexport namespace StringUtil {\n export function repeat(s: string, n: number): string {\n return slug(s).repeat(n);\n }\n\n export function slug(s: string): string {\n return s.toLowerCase().replace(/\\s+/g, \"-\");\n }\n\n export class Builder {\n private parts: string[] = [];\n add(part: string): this {\n this.parts.push(slug(part));\n return this;\n }\n build(): string {\n return this.parts.join(\"/\");\n }\n }\n}\n\n/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */\nexport function classify(items: T[]): Record {\n function keyOf(item: T): string {\n return item.name.charAt(0);\n }\n const out: Record = {};\n for (const item of items) {\n const k = keyOf(item);\n (out[k] ??= []).push(item);\n }\n return out;\n}\n","imports":[],"exports":[],"comments":[{"content":"/** A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures. */","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106},{"content":"/** Generic top-level function with a nested helper, to exercise inner_callables + generics. */","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"types":{"StringUtil":{"id":"can://slim/typescript/src/util.ts/StringUtil","kind":"namespace","span":{"start":[2,1],"end":[21,2],"bytes":[106,543]},"name":"StringUtil","signature":"src/util.StringUtil","comments":[{"content":"A namespace with nested declarations, to exercise the namespaces{} collection + nested signatures.","is_docstring":true,"start_line":1,"end_line":1,"start_column":1,"end_column":106}],"types":{"Builder":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder","kind":"class","span":{"start":[11,3],"end":[20,4],"bytes":[328,541]},"name":"Builder","signature":"src/util.StringUtil.Builder","comments":[],"decorators":[],"base_classes":[],"implements_types":[],"type_parameters":[],"callables":{"add":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","kind":"method","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"name":"add","signature":"src/util.StringUtil.Builder.add","comments":[],"decorators":[],"parameters":[{"name":"part","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":13,"end_line":13,"start_column":9,"end_column":21,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0"}],"type_parameters":[],"return_type":"this","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"14:7":{"kind":"call","span":{"start":[14,7],"end":[14,34],"bytes":[421,448]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["string"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7"},"14:23":{"kind":"call","span":{"start":[14,23],"end":[14,33],"bytes":[437,447]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:23"},"@entry":{"kind":"entry","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@entry"},"15:7":{"kind":"statement","span":{"start":[15,7],"end":[15,19],"bytes":[456,468]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@15:7"},"@exit":{"kind":"exit","span":{"start":[13,5],"end":[16,6],"bytes":[389,474]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@exit"},"@formal_in:0":{"kind":"formal_in","of":"part","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_out"},"14:7/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"14:7","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7/actual_in:0"},"14:7/actual_out":{"kind":"actual_out","of":"$ret","parent":"14:7","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"14:7","kind":"fallthrough"},{"src":"14:7","dst":"@exit","kind":"exception"},{"src":"14:7","dst":"15:7","kind":"fallthrough"},{"src":"15:7","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"14:7"},{"src":"14:7","dst":"15:7"}],"ddg":[{"src":"@entry","dst":"14:7","var":"part","prov":["reaching-defs"]},{"src":"@entry","dst":"14:7","var":"this.parts.push","prov":["reaching-defs"]},{"src":"@entry","dst":"15:7","var":"this","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"14:7","var":"part","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"14:7/actual_in:0","var":"part","prov":["reaching-defs"]},{"src":"14:7/actual_out","dst":"14:7","var":"$ret","prov":["reaching-defs"]},{"src":"15:7","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"14:7/actual_in:0","dst":"14:7/actual_out"}]},"build":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","kind":"method","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"name":"build","signature":"src/util.StringUtil.Builder.build","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"18:14":{"kind":"call","span":{"start":[18,14],"end":[18,34],"bytes":[510,530]},"callee":"can://slim/@external/(builtin)/join","method_name":"join","receiver_expr":"this.parts","receiver_type":"string[]","argument_types":["\"/\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:14"},"@entry":{"kind":"entry","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@entry"},"18:7":{"kind":"statement","span":{"start":[18,7],"end":[18,35],"bytes":[503,531]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:7"},"@exit":{"kind":"exit","span":{"start":[17,5],"end":[19,6],"bytes":[479,537]},"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@exit"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@formal_out"},"18:7/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"18:7","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:7/actual_in:0"},"18:7/actual_out":{"kind":"actual_out","of":"$ret","parent":"18:7","id":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@18:7/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"18:7","kind":"fallthrough"},{"src":"18:7","dst":"@exit","kind":"exception"},{"src":"18:7","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"18:7"}],"ddg":[{"src":"@entry","dst":"18:7","var":"this.parts.join","prov":["reaching-defs"]},{"src":"18:7","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"18:7/actual_in:0","dst":"18:7/actual_out"}]},"constructor":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","kind":"constructor","span":{"start":[0,0],"end":[0,0],"bytes":[0,0]},"name":"constructor","signature":"src/util.StringUtil.Builder.constructor","comments":[],"decorators":[],"parameters":[],"type_parameters":[],"cyclomatic_complexity":0,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":true,"overload_signatures":[],"body":{},"entrypoints":[],"is_entrypoint":false}},"fields":{"parts":{"id":"can://slim/typescript/src/util.ts/StringUtil/Builder/parts","kind":"field","span":{"start":[12,5],"end":[12,34],"bytes":[355,384]},"name":"parts","type":"string[]","comments":[],"decorators":[],"initializer":"[]","accessibility":"private","is_static":false,"is_readonly":false,"is_optional":false,"is_abstract":false}},"is_abstract":false,"is_exported":true,"is_ambient":false,"entrypoints":[],"is_entrypoint":false}},"functions":{"repeat":{"id":"can://slim/typescript/src/util.ts/StringUtil/repeat","kind":"function","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"name":"repeat","signature":"src/util.StringUtil.repeat","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":26,"end_column":35,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0"},{"name":"n","type":"number","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":3,"end_line":3,"start_column":37,"end_column":46,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"4:12":{"kind":"call","span":{"start":[4,12],"end":[4,29],"bytes":[204,221]},"callee":"can://slim/@external/(builtin)/repeat","method_name":"repeat","receiver_expr":"slug(s)","receiver_type":"string","argument_types":["number"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12"},"4:12/2":{"kind":"call","span":{"start":[4,12],"end":[4,19],"bytes":[204,211]},"callee":"can://slim/typescript/src/util.ts/StringUtil/slug","method_name":"slug","argument_types":["string"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:12/2"},"@entry":{"kind":"entry","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@entry"},"4:5":{"kind":"statement","span":{"start":[4,5],"end":[4,30],"bytes":[197,222]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5"},"@exit":{"kind":"exit","span":{"start":[3,3],"end":[5,4],"bytes":[138,226]},"id":"can://slim/typescript/src/util.ts/StringUtil/repeat@exit"},"@formal_in:0":{"kind":"formal_in","of":"s","id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0"},"@formal_in:1":{"kind":"formal_in","of":"n","id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_out"},"4:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"4:5","id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5/actual_in:0"},"4:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"4:5","id":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"4:5","kind":"fallthrough"},{"src":"4:5","dst":"@exit","kind":"exception"},{"src":"4:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"4:5"}],"ddg":[{"src":"@entry","dst":"4:5","var":"n","prov":["reaching-defs"]},{"src":"@entry","dst":"4:5","var":"s","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"4:5","var":"s","prov":["reaching-defs"]},{"src":"@formal_in:1","dst":"4:5","var":"n","prov":["reaching-defs"]},{"src":"@formal_in:1","dst":"4:5/actual_in:0","var":"n","prov":["reaching-defs"]},{"src":"4:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]},{"src":"4:5/actual_out","dst":"4:5","var":"$ret","prov":["reaching-defs"]}],"summary":[{"src":"4:5/actual_in:0","dst":"4:5/actual_out"}]},"slug":{"id":"can://slim/typescript/src/util.ts/StringUtil/slug","kind":"function","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"name":"slug","signature":"src/util.StringUtil.slug","comments":[],"decorators":[],"parameters":[{"name":"s","type":"string","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":7,"end_line":7,"start_column":24,"end_column":33,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"8:12":{"kind":"call","span":{"start":[8,12],"end":[8,48],"bytes":[283,319]},"callee":"can://slim/@external/(builtin)/replace","method_name":"replace","receiver_expr":"s.toLowerCase()","receiver_type":"string","argument_types":["RegExp","\"-\""],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12"},"8:12/2":{"kind":"call","span":{"start":[8,12],"end":[8,27],"bytes":[283,298]},"callee":"can://slim/@external/(builtin)/toLowerCase","method_name":"toLowerCase","receiver_expr":"s","receiver_type":"string","argument_types":[],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:12/2"},"@entry":{"kind":"entry","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@entry"},"8:5":{"kind":"statement","span":{"start":[8,5],"end":[8,49],"bytes":[276,320]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:5"},"@exit":{"kind":"exit","span":{"start":[7,3],"end":[9,4],"bytes":[230,324]},"id":"can://slim/typescript/src/util.ts/StringUtil/slug@exit"},"@formal_in:0":{"kind":"formal_in","of":"s","id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_out"},"8:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"8:5","id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:5/actual_in:0"},"8:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"8:5","id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:5/actual_out"},"8:5/actual_in:1":{"kind":"actual_in","of":"arg1","parent":"8:5","id":"can://slim/typescript/src/util.ts/StringUtil/slug@8:5/actual_in:1"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"8:5","kind":"fallthrough"},{"src":"8:5","dst":"@exit","kind":"exception"},{"src":"8:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"8:5"}],"ddg":[{"src":"@entry","dst":"8:5","var":"s.toLowerCase","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"8:5","var":"s.toLowerCase","prov":["reaching-defs"]},{"src":"8:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"8:5/actual_in:0","dst":"8:5/actual_out"},{"src":"8:5/actual_in:1","dst":"8:5/actual_out"}]}},"fields":{},"is_exported":true,"is_ambient":false}},"functions":{"classify":{"id":"can://slim/typescript/src/util.ts/classify","kind":"function","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"name":"classify","signature":"src/util.classify","comments":[{"content":"Generic top-level function with a nested helper, to exercise inner_callables + generics.","is_docstring":true,"start_line":23,"end_line":23,"start_column":1,"end_column":96}],"decorators":[],"parameters":[{"name":"items","type":"T[]","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":24,"end_line":24,"start_column":54,"end_column":64,"id":"can://slim/typescript/src/util.ts/classify@formal_in:0"}],"type_parameters":[{"name":"T","constraint":"{ name: string }"}],"return_type":"Record","cyclomatic_complexity":2,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":true,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"30:15":{"kind":"call","span":{"start":[30,15],"end":[30,26],"bytes":[884,895]},"callee":"can://slim/typescript/src/util.ts/classify/keyOf","method_name":"keyOf","argument_types":["T"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@30:15"},"31:5":{"kind":"call","span":{"start":[31,5],"end":[31,31],"bytes":[901,927]},"callee":"can://slim/@external/(builtin)/push","method_name":"push","receiver_expr":"(out[k] ??= [])","receiver_type":"T[]","argument_types":["T"],"type_arguments":[],"return_type":"number","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify@31:5"},"@entry":{"kind":"entry","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"id":"can://slim/typescript/src/util.ts/classify@entry"},"25:3":{"kind":"statement","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify@25:3"},"28:3":{"kind":"statement","span":{"start":[28,3],"end":[28,39],"bytes":[803,839]},"id":"can://slim/typescript/src/util.ts/classify@28:3"},"29:3":{"kind":"statement","span":{"start":[29,3],"end":[32,4],"bytes":[842,932]},"id":"can://slim/typescript/src/util.ts/classify@29:3"},"30:5":{"kind":"statement","span":{"start":[30,5],"end":[30,27],"bytes":[874,896]},"id":"can://slim/typescript/src/util.ts/classify@30:5"},"33:3":{"kind":"statement","span":{"start":[33,3],"end":[33,14],"bytes":[935,946]},"id":"can://slim/typescript/src/util.ts/classify@33:3"},"@exit":{"kind":"exit","span":{"start":[24,1],"end":[34,2],"bytes":[641,948]},"id":"can://slim/typescript/src/util.ts/classify@exit"},"@formal_in:0":{"kind":"formal_in","of":"items","id":"can://slim/typescript/src/util.ts/classify@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/classify@formal_out"},"30:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"30:5","id":"can://slim/typescript/src/util.ts/classify@30:5/actual_in:0"},"30:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"30:5","id":"can://slim/typescript/src/util.ts/classify@30:5/actual_out"},"31:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"31:5","id":"can://slim/typescript/src/util.ts/classify@31:5/actual_in:0"},"31:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"31:5","id":"can://slim/typescript/src/util.ts/classify@31:5/actual_out"}},"callables":{"keyOf":{"id":"can://slim/typescript/src/util.ts/classify/keyOf","kind":"function","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"name":"keyOf","signature":"src/util.classify.keyOf","comments":[],"decorators":[],"parameters":[{"name":"item","type":"T","is_optional":false,"is_rest":false,"is_readonly":false,"decorators":[],"start_line":25,"end_line":25,"start_column":18,"end_column":25,"id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0"}],"type_parameters":[],"return_type":"string","cyclomatic_complexity":1,"is_static":false,"is_abstract":false,"is_async":false,"is_generator":false,"is_optional":false,"is_readonly":false,"is_exported":false,"is_ambient":false,"is_implicit":false,"overload_signatures":[],"body":{"26:12":{"kind":"call","span":{"start":[26,12],"end":[26,31],"bytes":[776,795]},"callee":"can://slim/@external/(builtin)/charAt","method_name":"charAt","receiver_expr":"item.name","receiver_type":"string","argument_types":["0"],"type_arguments":[],"return_type":"string","is_constructor_call":false,"is_optional_chain":false,"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:12"},"@entry":{"kind":"entry","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@entry"},"26:5":{"kind":"statement","span":{"start":[26,5],"end":[26,32],"bytes":[769,796]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@26:5"},"@exit":{"kind":"exit","span":{"start":[25,3],"end":[27,4],"bytes":[731,800]},"id":"can://slim/typescript/src/util.ts/classify/keyOf@exit"},"@formal_in:0":{"kind":"formal_in","of":"item","id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0"},"@formal_out":{"kind":"formal_out","of":"$ret","id":"can://slim/typescript/src/util.ts/classify/keyOf@formal_out"},"26:5/actual_in:0":{"kind":"actual_in","of":"arg0","parent":"26:5","id":"can://slim/typescript/src/util.ts/classify/keyOf@26:5/actual_in:0"},"26:5/actual_out":{"kind":"actual_out","of":"$ret","parent":"26:5","id":"can://slim/typescript/src/util.ts/classify/keyOf@26:5/actual_out"}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"26:5","kind":"fallthrough"},{"src":"26:5","dst":"@exit","kind":"exception"},{"src":"26:5","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"26:5"}],"ddg":[{"src":"@entry","dst":"26:5","var":"item.name.charAt","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"26:5","var":"item.name.charAt","prov":["reaching-defs"]},{"src":"26:5","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"26:5/actual_in:0","dst":"26:5/actual_out"}]}},"entrypoints":[],"is_entrypoint":false,"cfg":[{"src":"@entry","dst":"25:3","kind":"fallthrough"},{"src":"25:3","dst":"@exit","kind":"exception"},{"src":"25:3","dst":"28:3","kind":"fallthrough"},{"src":"28:3","dst":"29:3","kind":"fallthrough"},{"src":"29:3","dst":"30:5","kind":"true"},{"src":"29:3","dst":"33:3","kind":"false"},{"src":"30:5","dst":"@exit","kind":"exception"},{"src":"30:5","dst":"31:5","kind":"fallthrough"},{"src":"31:5","dst":"@exit","kind":"exception"},{"src":"31:5","dst":"29:3","kind":"loop_back"},{"src":"33:3","dst":"@exit","kind":"return"}],"cdg":[{"src":"@entry","dst":"25:3"},{"src":"25:3","dst":"28:3"},{"src":"25:3","dst":"29:3"},{"src":"29:3","dst":"30:5"},{"src":"29:3","dst":"33:3"},{"src":"30:5","dst":"31:5"},{"src":"31:5","dst":"29:3"}],"ddg":[{"src":"@entry","dst":"29:3","var":"items","prov":["reaching-defs"]},{"src":"@formal_in:0","dst":"29:3","var":"items","prov":["reaching-defs"]},{"src":"28:3","dst":"31:5","var":"out[*]","prov":["reaching-defs"]},{"src":"28:3","dst":"33:3","var":"out","prov":["reaching-defs"]},{"src":"29:3","dst":"30:5","var":"item","prov":["reaching-defs"]},{"src":"29:3","dst":"30:5/actual_in:0","var":"item","prov":["reaching-defs"]},{"src":"29:3","dst":"31:5","var":"item","prov":["reaching-defs"]},{"src":"30:5","dst":"31:5","var":"k","prov":["reaching-defs"]},{"src":"30:5/actual_out","dst":"30:5","var":"$ret","prov":["reaching-defs"]},{"src":"31:5","dst":"31:5","var":"out[*]","prov":["reaching-defs"]},{"src":"31:5","dst":"33:3","var":"out","prov":["reaching-defs"]},{"src":"33:3","dst":"@formal_out","var":"return","prov":["reaching-defs"]}],"summary":[{"src":"30:5/actual_in:0","dst":"30:5/actual_out"},{"src":"31:5/actual_in:0","dst":"31:5/actual_out"}]}},"fields":{},"is_tsx":false,"is_declaration_file":false,"content_hash":"54886cff7e11ccadc987571f508b2aef2f324b14e63d8ad52100499851d130fa"}},"call_graph":[{"src":"can://slim/typescript/src/controllers.ts","dst":"can://slim/typescript/src/controllers.ts/Controller","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/index.ts","dst":"can://slim/typescript/src/index.ts/main","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Param","prov":["tsc","defuse"],"weight":2},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/services.ts/UserService/describeAll","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/UserService/createGuest","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/list","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/controllers.ts/UserController/show","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/services.ts/announce","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/models.ts/Robot/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","prov":["tsc"],"weight":2},{"src":"can://slim/typescript/src/index.ts/main","dst":"can://slim/@external/(builtin)/log","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/models.ts/User/constructor","dst":"can://slim/typescript/src/models.ts/Entity/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Named/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/announce","dst":"can://slim/typescript/src/models.ts/Robot/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/services.ts/nextId","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/typescript/src/models.ts/User/constructor","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/create","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/makeGuestName","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest","dst":"can://slim/typescript/src/services.ts/UserService/create","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/@external/(builtin)/map","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll/","dst":"can://slim/typescript/src/models.ts/User/describe","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/loginAll","dst":"can://slim/typescript/src/models.ts/User/recordLogin","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/typescript/src/util.ts/classify/keyOf","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/classify/keyOf","dst":"can://slim/@external/(builtin)/charAt","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/@external/(builtin)/repeat","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/replace","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug","dst":"can://slim/@external/(builtin)/toLowerCase","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/@external/(builtin)/push","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add","dst":"can://slim/typescript/src/util.ts/StringUtil/slug","prov":["tsc"],"weight":1},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/build","dst":"can://slim/@external/(builtin)/join","prov":["import"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/list","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/controllers.ts/UserController/show","dst":"can://slim/typescript/src/controllers.ts/Get","prov":["defuse"],"weight":1},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll","dst":"can://slim/typescript/src/services.ts/UserService/describeAll/","prov":["defuse"],"weight":1}],"param_in":[{"src":"can://slim/typescript/src/controllers.ts/UserController/show@20:5","dst":"can://slim/typescript/src/services.ts/UserService/create@entry","var":"src/services.nextId"},{"src":"can://slim/typescript/src/controllers.ts/UserController/show@20:5/actual_in:0","dst":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0","var":"name"},{"src":"can://slim/typescript/src/index.ts/main@11:3/actual_in:0","dst":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_in:0","var":"service"},{"src":"can://slim/typescript/src/index.ts/main@13:3","dst":"can://slim/typescript/src/controllers.ts/UserController/show@entry","var":"src/services.nextId"},{"src":"can://slim/typescript/src/index.ts/main@13:3/actual_in:0","dst":"can://slim/typescript/src/controllers.ts/UserController/show@formal_in:0","var":"id"},{"src":"can://slim/typescript/src/index.ts/main@16:3/actual_in:0","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0","var":"id"},{"src":"can://slim/typescript/src/index.ts/main@16:3/actual_in:0","dst":"can://slim/typescript/src/services.ts/announce@formal_in:0","var":"thing"},{"src":"can://slim/typescript/src/index.ts/main@16:3/actual_in:1","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1","var":"name"},{"src":"can://slim/typescript/src/index.ts/main@16:3/actual_in:2","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2","var":"role"},{"src":"can://slim/typescript/src/index.ts/main@17:3/actual_in:0","dst":"can://slim/typescript/src/models.ts/Robot/constructor@formal_in:0","var":"name"},{"src":"can://slim/typescript/src/index.ts/main@17:3/actual_in:0","dst":"can://slim/typescript/src/services.ts/announce@formal_in:0","var":"thing"},{"src":"can://slim/typescript/src/index.ts/main@19:3/actual_in:0","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:0","var":"s"},{"src":"can://slim/typescript/src/index.ts/main@19:3/actual_in:1","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_in:1","var":"n"},{"src":"can://slim/typescript/src/index.ts/main@21:3/actual_in:0","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_in:0","var":"part"},{"src":"can://slim/typescript/src/index.ts/main@7:3/actual_in:0","dst":"can://slim/typescript/src/services.ts/UserService/constructor@formal_in:0","var":"startId"},{"src":"can://slim/typescript/src/index.ts/main@8:3","dst":"can://slim/typescript/src/services.ts/UserService/create@entry","var":"src/services.nextId"},{"src":"can://slim/typescript/src/index.ts/main@8:3/actual_in:0","dst":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0","var":"name"},{"src":"can://slim/typescript/src/index.ts/main@8:3/actual_in:1","dst":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1","var":"role"},{"src":"can://slim/typescript/src/index.ts/main@9:3","dst":"can://slim/typescript/src/services.ts/UserService/createGuest@entry","var":"src/services.nextId"},{"src":"can://slim/typescript/src/models.ts/User/constructor@40:5/actual_in:0","dst":"can://slim/typescript/src/models.ts/Entity/constructor@formal_in:0","var":"id"},{"src":"can://slim/typescript/src/services.ts/UserService/create@25:5/actual_in:0","dst":"can://slim/typescript/src/services.ts/nextId@formal_in:0","var":"n"},{"src":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:0","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:0","var":"id"},{"src":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:1","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:1","var":"name"},{"src":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_in:2","dst":"can://slim/typescript/src/models.ts/User/constructor@formal_in:2","var":"role"},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5/actual_in:0","dst":"can://slim/typescript/src/services.ts/makeGuestName@formal_in:0","var":"seed"},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5","dst":"can://slim/typescript/src/services.ts/UserService/create@entry","var":"src/services.nextId"},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_in:0","dst":"can://slim/typescript/src/services.ts/UserService/create@formal_in:0","var":"name"},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_in:1","dst":"can://slim/typescript/src/services.ts/UserService/create@formal_in:1","var":"role"},{"src":"can://slim/typescript/src/util.ts/classify@30:5/actual_in:0","dst":"can://slim/typescript/src/util.ts/classify/keyOf@formal_in:0","var":"item"},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7/actual_in:0","dst":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0","var":"s"},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5/actual_in:0","dst":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_in:0","var":"s"}],"param_out":[{"src":"can://slim/typescript/src/controllers.ts/UserController/constructor@formal_out","dst":"can://slim/typescript/src/index.ts/main@11:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/controllers.ts/UserController/list@formal_out","dst":"can://slim/typescript/src/index.ts/main@12:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/controllers.ts/UserController/show@formal_out","dst":"can://slim/typescript/src/index.ts/main@13:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/Entity/constructor@formal_out","dst":"can://slim/typescript/src/models.ts/User/constructor@40:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/Robot/constructor@formal_out","dst":"can://slim/typescript/src/index.ts/main@17:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/User/constructor@formal_out","dst":"can://slim/typescript/src/index.ts/main@16:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/User/constructor@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/create@26:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/User/describe@formal_out","dst":"can://slim/typescript/src/controllers.ts/UserController/show@21:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/User/describe@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/describeAll/@37:34/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/models.ts/User/recordLogin@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/loginAll@43:7/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/announce@formal_out","dst":"can://slim/typescript/src/index.ts/main@16:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/announce@formal_out","dst":"can://slim/typescript/src/index.ts/main@17:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/makeGuestName@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/createGuest@32:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/nextId@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/create@25:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/constructor@formal_out","dst":"can://slim/typescript/src/index.ts/main@7:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/create@formal_out","dst":"can://slim/typescript/src/controllers.ts/UserController/show@20:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/create@formal_out","dst":"can://slim/typescript/src/index.ts/main@8:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/create@formal_out","dst":"can://slim/typescript/src/services.ts/UserService/createGuest@33:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/createGuest@formal_out","dst":"can://slim/typescript/src/index.ts/main@9:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/services.ts/UserService/describeAll@formal_out","dst":"can://slim/typescript/src/controllers.ts/UserController/list@26:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/classify/keyOf@formal_out","dst":"can://slim/typescript/src/util.ts/classify@30:5/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@formal_out","dst":"can://slim/typescript/src/index.ts/main@21:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/StringUtil/Builder/build@formal_out","dst":"can://slim/typescript/src/index.ts/main@21:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/StringUtil/repeat@formal_out","dst":"can://slim/typescript/src/index.ts/main@19:3/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_out","dst":"can://slim/typescript/src/util.ts/StringUtil/Builder/add@14:7/actual_out","var":"$ret"},{"src":"can://slim/typescript/src/util.ts/StringUtil/slug@formal_out","dst":"can://slim/typescript/src/util.ts/StringUtil/repeat@4:5/actual_out","var":"$ret"}],"artifacts":{"package.json":{"id":"can://slim/artifact/package.json","kind":"artifact","path":"package.json","format":"json","roles":["dependency-manifest","tool-config"],"size_bytes":88,"sha256":"277f174033b3f17dcd3ba9a550b53289624f034606303cef18a3f84ab7156c67","source":"{\n \"name\": \"sample-app\",\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"private\": true\n}\n","extraction":"none","config_keys":[]},"tsconfig.json":{"id":"can://slim/artifact/tsconfig.json","kind":"artifact","path":"tsconfig.json","format":"json","roles":["tool-config"],"size_bytes":289,"sha256":"72f24fc616456ab556dd8e7c886264214cb344547b32b972eb476467af0a9cab","source":"{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"bundler\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"skipLibCheck\": true,\n \"experimentalDecorators\": true,\n \"emitDecoratorMetadata\": true\n },\n \"include\": [\"src/**/*.ts\"]\n}\n","extraction":"full","config_keys":[{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.target","key":"compilerOptions.target","namespace":"json","value":"ES2022","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.module","key":"compilerOptions.module","namespace":"json","value":"ESNext","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.moduleResolution","key":"compilerOptions.moduleResolution","namespace":"json","value":"bundler","references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.strict","key":"compilerOptions.strict","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.esModuleInterop","key":"compilerOptions.esModuleInterop","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.skipLibCheck","key":"compilerOptions.skipLibCheck","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.experimentalDecorators","key":"compilerOptions.experimentalDecorators","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/compilerOptions.emitDecoratorMetadata","key":"compilerOptions.emitDecoratorMetadata","namespace":"json","value":true,"references":[]},{"id":"can://slim/artifact/tsconfig.json@key/include.0","key":"include.0","namespace":"json","value":"src/**/*.ts","references":[]}]}},"dependencies":[],"unresolved_imports":[],"config_uses":[],"config_reads":[],"entrypoint_report":{"frameworks_detected":[],"rulesets":["shipped"],"unresolved":{"Get":2,"Controller":1},"errors":[]},"external_symbols":{"can://slim/@external/(builtin)/log":{"id":"can://slim/@external/(builtin)/log","kind":"external","module":"(builtin)","name":"log"},"can://slim/@external/(builtin)/push":{"id":"can://slim/@external/(builtin)/push","kind":"external","module":"(builtin)","name":"push"},"can://slim/@external/(builtin)/map":{"id":"can://slim/@external/(builtin)/map","kind":"external","module":"(builtin)","name":"map"},"can://slim/@external/(builtin)/charAt":{"id":"can://slim/@external/(builtin)/charAt","kind":"external","module":"(builtin)","name":"charAt"},"can://slim/@external/(builtin)/repeat":{"id":"can://slim/@external/(builtin)/repeat","kind":"external","module":"(builtin)","name":"repeat"},"can://slim/@external/(builtin)/replace":{"id":"can://slim/@external/(builtin)/replace","kind":"external","module":"(builtin)","name":"replace"},"can://slim/@external/(builtin)/toLowerCase":{"id":"can://slim/@external/(builtin)/toLowerCase","kind":"external","module":"(builtin)","name":"toLowerCase"},"can://slim/@external/(builtin)/join":{"id":"can://slim/@external/(builtin)/join","kind":"external","module":"(builtin)","name":"join"}},"synthesized_callables":{"can://slim/typescript/src/controllers.ts/Controller@5:10":{"id":"can://slim/typescript/src/controllers.ts/Controller/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Get@8:10":{"id":"can://slim/typescript/src/controllers.ts/Get/","kind":"callable"},"can://slim/typescript/src/controllers.ts/Param@11:10":{"id":"can://slim/typescript/src/controllers.ts/Param/","kind":"callable"},"can://slim/typescript/src/services.ts/UserService/describeAll@37:27":{"id":"can://slim/typescript/src/services.ts/UserService/describeAll/","kind":"callable"}}}} \ No newline at end of file diff --git a/uv.lock b/uv.lock index 4f0ea175..03ada0d4 100644 --- a/uv.lock +++ b/uv.lock @@ -351,8 +351,8 @@ requires-dist = [ { name = "cldk", extras = ["java"], marker = "extra == 'all'" }, { name = "cldk", extras = ["neo4j"], marker = "extra == 'all'" }, { name = "codeanalyzer-java", marker = "extra == 'java'", specifier = "==3.2.0" }, - { name = "codeanalyzer-python", specifier = "==1.5.1" }, - { name = "codeanalyzer-typescript", specifier = "==1.5.3" }, + { name = "codeanalyzer-python", specifier = "==1.5.2" }, + { name = "codeanalyzer-typescript", specifier = "==1.6.0" }, { name = "neo4j", marker = "extra == 'neo4j'", specifier = ">=5.14,<7" }, { name = "networkx", specifier = ">=3.4.2,<4" }, { name = "pydantic", specifier = ">=2.10.6,<3" }, @@ -409,7 +409,7 @@ wheels = [ [[package]] name = "codeanalyzer-python" -version = "1.5.1" +version = "1.5.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "astor" }, @@ -426,21 +426,21 @@ dependencies = [ { name = "typing-extensions" }, { name = "uv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0f/ab/13d36b0a4d68c7b4696459e91cf7677e965a60b451e79e574d40a8709c51/codeanalyzer_python-1.5.1.tar.gz", hash = "sha256:8b7468acc2a1c079ba09b626be5947c8fc3075093cab47b5ff1a28d0a817fc43", size = 231699, upload-time = "2026-09-09T15:56:23.148Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/c1/c76ad3a531d02f2548a8128c17c33c01c0d5aec240bd8e0dad93411590c3/codeanalyzer_python-1.5.2.tar.gz", hash = "sha256:18b1d81c44f0e0f1ab8dcb36a144345c58a51a55394a1a2b359d92c97c43df84", size = 234282, upload-time = "2026-09-10T21:45:35.272Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/2d/39e0817c098c6cb0c2438805032e483203b973f2b1ff37ed23820827d1d1/codeanalyzer_python-1.5.1-py3-none-any.whl", hash = "sha256:492a16b6ba04b0fe809dfc58472405fecbf616c6da8d0fe18a2085d9b048c62c", size = 237286, upload-time = "2026-09-09T15:56:21.787Z" }, + { url = "https://files.pythonhosted.org/packages/60/12/61fbed9875b06c061b24fcf4363e96215431db86efd895a2f4bd966c1d4f/codeanalyzer_python-1.5.2-py3-none-any.whl", hash = "sha256:7c0e1ed0b91fde5376f5c0cae70d48f85e83b0ff9e737c923b37c8e3375e2cd2", size = 239571, upload-time = "2026-09-10T21:45:33.895Z" }, ] [[package]] name = "codeanalyzer-typescript" -version = "1.5.3" +version = "1.6.0" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/24/c30e345c8f70e3b2e87c218c87d93044d00182de70450071baca83450feb/codeanalyzer_typescript-1.5.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d1534de6c029a56bc544a9b62b86b634ba3cab70f6cd4fc1201163f8d87788de", size = 30873520, upload-time = "2026-09-09T14:08:04.365Z" }, - { url = "https://files.pythonhosted.org/packages/09/48/99380eda3988023e6498ed9c843f0ef107813d43e3296a48205f1df315ec/codeanalyzer_typescript-1.5.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1a2dac07dccb107e52ff8a3020ec4d266c253fdc3390d3fabf4384ca91838c56", size = 28271759, upload-time = "2026-09-09T14:08:07.877Z" }, - { url = "https://files.pythonhosted.org/packages/72/91/9b3bbc8a839b6e8e76ca3c1919e417cdfe6f7ddf8710e91440194426aee7/codeanalyzer_typescript-1.5.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:b6879aa73bf700e3185516b1adefee21ca7118b508702a08bc9c6172e63cf649", size = 39039182, upload-time = "2026-09-09T14:08:11.185Z" }, - { url = "https://files.pythonhosted.org/packages/55/7a/5065b204df9b81dd7a1814b4516a319ffa7e444db994fd878ab5a715244a/codeanalyzer_typescript-1.5.3-py3-none-manylinux2014_x86_64.whl", hash = "sha256:22bdb2ab91d6d9fd3deffe1f7b4bbc9527de323a6c0ffc318a2cb3484633b4e5", size = 39083432, upload-time = "2026-09-09T14:08:15.134Z" }, - { url = "https://files.pythonhosted.org/packages/d2/02/9b971f72b59a5f8a97fc761aba2dd3ef973be7d362a8ff28e19e8cc062b6/codeanalyzer_typescript-1.5.3-py3-none-win_amd64.whl", hash = "sha256:2ac639c455b7638c143f59417c12974e7bdab0f09e22347675b8327c822835c5", size = 42233359, upload-time = "2026-09-09T14:08:19.109Z" }, + { url = "https://files.pythonhosted.org/packages/f6/ad/510de3445b2017c1ef560fa392d0d3e78189b732594dd17a6646a353fcbd/codeanalyzer_typescript-1.6.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:410d2031393dee882580bc6060848dcd21574e7d5a98d53a898f71b3bd52b036", size = 30873592, upload-time = "2026-09-10T18:35:07.426Z" }, + { url = "https://files.pythonhosted.org/packages/3f/7b/e372a8867970b8c18aa9c4531112dba46a3e80f34575758e8433dcb6981c/codeanalyzer_typescript-1.6.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:8f36da2c5b8ebf7b2f5b5080a298b3c970be684db7db51bdf8e97072bcedadb5", size = 28271834, upload-time = "2026-09-10T18:35:11.281Z" }, + { url = "https://files.pythonhosted.org/packages/e5/09/e0028c84bbe4bfb80af09aea885bb1195ca5f26d09f529d644258aa21d91/codeanalyzer_typescript-1.6.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:c936e94ec70f415354fb1ba8df4e03c39bafce5c376afb995bcbe16a9650bc8d", size = 39039256, upload-time = "2026-09-10T18:35:15.323Z" }, + { url = "https://files.pythonhosted.org/packages/c4/cf/b623197514c258506ddf4182efd0228f276688447c60f64f4609ea2b49df/codeanalyzer_typescript-1.6.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:12f9aae1fed212345e98ea03abaaa2318691bcd2735bc3c4c61fb65068b23baa", size = 39083503, upload-time = "2026-09-10T18:35:20.094Z" }, + { url = "https://files.pythonhosted.org/packages/37/d0/10de246e0a78c9386e53cbed0dc664db9d1976a9ebcc9652b3f89e5fe1bf/codeanalyzer_typescript-1.6.0-py3-none-win_amd64.whl", hash = "sha256:5d8bd61b794e6159a513d15b40744fafebef3b99b1b891e516d9796090d872b9", size = 42233438, upload-time = "2026-09-10T18:35:24.808Z" }, ] [[package]] From 0a6ad2c54d1eacf94a2975a6fc87c53f1f74e20f Mon Sep 17 00:00:00 2001 From: Rahul Krishna Date: Thu, 10 Sep 2026 18:31:37 -0400 Subject: [PATCH 5/7] chore(release): 2.0.0-rc.6 --- CHANGELOG.md | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 2 +- uv.lock | 2 +- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6423a2e6..f07df1c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,74 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v2.0.0-rc.6] - 2026-09-10 + +The Java Neo4j backend stops being the lossy one about source text. Until now a graph-backed Java +analysis could answer *where* a node is far better than *what it says*: text existed only as +`:JCallable.code`, so a callable came back as its whole declaration where the local backend returned +the body block, a body node had no text at all, and a module-scope `locate` returned `""`. The +analyzer closed that gap in 3.2.0; this release takes it up, and moves the sibling pins to the +releases that closed the same gap for Python and TypeScript. + +### Breaking + +**The Java Neo4j attach floor moves to codeanalyzer-java 3.2.0.** A graph emitted by 3.1.x — served +silently until now — is refused at attach, naming what was found and the floor. + +The floor moves rather than degrading gracefully because the degradation would be silent and would +look like data. A 3.1.x graph has no `:JModule.source` and no byte offsets, so every text answer +would come back empty or as the old whole-declaration string, from accessors this release documents +as returning the same text as the local backend. An agent cannot tell "this node has no text" from +"this graph predates the property" — so the check belongs at attach, once, where it can say so. + +**Migration:** re-emit with `codeanalyzer-java 3.2.0 --emit neo4j`. Wipe the database first when the +graph predates 3.1.1, which moved the `can://` grammar. + +### Changed + +**Text is the same on both Java backends.** `JCallable.code`, `get_source`, `LocateResult.source` and +`describe` answer the same slice of the same file at every granularity — a callable's body block, a +type's or field's or local's declaration, a single statement or call site, and a module's whole text at +module scope. Each is a byte slice of `:JModule.source` taken at the node's own offsets, so the live +suites assert **equality** rather than `endswith` or "the same length". + +Three positions still have no text, on **both** backends and for the same reason each time — there is +nothing in the file to point at: an implicit compiler-generated `()`, an `@external` callable, and +a `resolve_value` ref (a `formal_in` vertex is a dataflow position, not a region of the file). +`module_source_unavailable` survives as a **data** diagnostic: it now fires on a module whose text the +analyzer could not read or decode, and on nothing else. + +Two removals fall out of it. `:JCallable.code` is no longer read — the slice replaces it — and +`body_end_byte` was never needed: across both committed fixtures, all 1,182 callables carrying both +spans end their body exactly where their declaration ends, because a Java declaration's last character +*is* its body's closing brace. That is asserted in the fixture builder rather than written down. + +**Analyzer pins move to `codeanalyzer-python==1.5.2` and `codeanalyzer-typescript==1.6.0`** +(`codeanalyzer-java` is already at 3.2.0). Both are Neo4j-projection-only conformance fixes: python +1.5.2 adds `:PyModule.source`, all six span properties wherever a span is declared, +`:PyVariable.value_json`, `:PyBodyNode.callee_signature`, `PY_IMPORTS.positions_json` and a span on +`PY_DECORATED_BY`; typescript 1.6.0 adds `:TSModule.source` and the four new span properties across ten +labels. Neither changes `analysis.json` — the TypeScript fixtures regenerated with the 1.6.0 wheel are +byte-identical to the 1.5.3 generation at all four levels apart from the `analyzer.version` stamp. + +**Neither sibling floor moves.** They stay 1.5.0 for Python and 1.5.2 for TypeScript: a floor move is +what would let the SDK *read* that new text, and that is uptake work the size of this release's Java +half, tracked in #396 and #391. The pin is what the SDK installs; the floor is what it requires of a +graph. Every sentence in the docs that read "the graph does not carry this" now says the SDK does not +read it, and names the issue that will. + +One thing does improve for free on a re-emitted Python graph: a call site's columns. The +reconstruction already reads `start_column` with a `-1` default, so 1.5.2 supplies real values and an +older graph still answers `-1` — data-driven, no version branch. + +### Verification + +The mocked, backend-contract and E2E tiers are green, and the Java E2E ran against the real 3.2.0 jar. +The **live** Java tiers — the ones that assert byte-for-byte equality across the two backends on +daytrader8 — assert the new behaviour but have not been run against a 3.2.0-emitted graph: the +verification corpus holds a 3.1.1 graph, which this release's own floor now refuses. Re-emitting it is +the outstanding verification debt, recorded rather than glossed. + ## [v2.0.0-rc.5] - 2026-09-10 Two changes, and they are the two halves of one question: what should happen when an analyzer ships diff --git a/pyproject.toml b/pyproject.toml index da8b19e1..4ef0e17a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cldk" -version = "2.0.0-rc.5" +version = "2.0.0-rc.6" description = "The official Python SDK for Codellm-Devkit." readme = "README.md" license = { text = "Apache-2.0" } diff --git a/uv.lock b/uv.lock index 03ada0d4..fb3df067 100644 --- a/uv.lock +++ b/uv.lock @@ -300,7 +300,7 @@ wheels = [ [[package]] name = "cldk" -version = "2.0.0rc5" +version = "2.0.0rc6" source = { editable = "." } dependencies = [ { name = "codeanalyzer-python" }, From 959b0418da2725fd3ed3721b173d4c5a2a96147d Mon Sep 17 00:00:00 2001 From: Rahul Krishna Date: Fri, 11 Sep 2026 12:13:23 -0400 Subject: [PATCH 6/7] =?UTF-8?q?feat(java):=20view=20dispatches=20=E2=80=94?= =?UTF-8?q?=20JViewDispatch=20models,=20get=5Fview=5Fdispatches=20/=20get?= =?UTF-8?q?=5Fview=5Fdispatchers=20/=20get=5Funresolved=5Fview=5Fdispatche?= =?UTF-8?q?s,=20Neo4j=20J=5FDISPATCHES=5FTO;=20pin=20codeanalyzer-java=203?= =?UTF-8?q?.3.3=20(#404)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three accessors on JavaAnalysis over both backends, one implementation on the contract; the Neo4j backend reads J_DISPATCHES_TO back and refuses the JSON-only unresolved record. The layer is the one overlay gated on the analyzer generation, because 3.3.x added no always-present key to probe. Pin 3.2.0 -> 3.3.3; release/2.0 absorbs main at rc.6. --- CHANGELOG.md | 58 ++++++ cldk/analysis/java/backend.py | 121 +++++++++++++ .../java/codeanalyzer/codeanalyzer.py | 12 ++ cldk/analysis/java/java_analysis.py | 43 +++++ cldk/analysis/java/neo4j/neo4j_backend.py | 31 ++++ cldk/models/java/__init__.py | 4 + cldk/models/java/models.py | 47 ++++- docs/agent-api-reference.md | 18 +- pyproject.toml | 4 +- tests/analysis/java/test_java_e2e.py | 21 +++ .../analysis/java/test_java_neo4j_backend.py | 7 + .../analysis/java/test_java_public_surface.py | 3 + .../java/test_java_view_dispatches.py | 167 ++++++++++++++++++ uv.lock | 8 +- 14 files changed, 535 insertions(+), 9 deletions(-) create mode 100644 tests/analysis/java/test_java_view_dispatches.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f07df1c4..4382bcd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,64 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v2.0.0-rc.7] - 2026-09-11 + +The Java facade learns the view layer codeanalyzer-java 3.3.0–3.3.2 added, and the 2.0 line takes up +everything rc.6 shipped from `main` (the 3.2.0 text model and the sibling-analyzer pins) — this is +the first release cut from `release/2.0` that contains rc.6. + +### Added + +**Java view dispatches** (`python-sdk#404`, spec `codellm-devkit/.github` +`docs/design/specs/2026-09-11-java-view-templates-and-dispatch.md`). JSP, Facelets and Thymeleaf +templates are artifacts with `roles: ["view-template"]`, and the analyzer now says which code reaches +one. Three accessors on `JavaAnalysis`, both backends: + +- `get_view_dispatches(view=None) -> List[JViewDispatch]` — every resolved dispatch: the body node + that hands the request over (a `forward` / `include` / `sendRedirect` call, a `ModelAndView` + construction or `setViewName`, or a Spring controller's `return`) and the artifact it reaches, + with `via` naming the mechanism and `prov` the tier. `literal` and `dataflow` mean exactly one + target; `table` (3.3.1) is a may-dispatch over a static string table, one edge per entry, from + the same site. `view` filters by a segment-aligned suffix of the artifact's path. +- `get_view_dispatchers(path) -> List[JCallableOverview]` — the same edges resolved to the callables + that own the dispatching sites. +- `get_unresolved_view_dispatches() -> List[JViewDispatchUnresolved]` — what closed on nothing (a + variable target, a servlet URL, a view name matching two templates), with its reason and the tiers + attempted. JSON-only: the graph has no node for a target that resolved to nothing, so the Neo4j + backend refuses this one rather than answering `[]`. + +Two models, `JViewDispatch` and `JViewDispatchUnresolved`, on `JApplication.view_dispatches` / +`.view_dispatches_unresolved`; the Neo4j backend reads `J_DISPATCHES_TO` back into the former. + +One rule stated because it is the only one of its kind: **this layer is gated on the analyzer +generation.** The 3.1.0 config trio is probed by an always-present sibling key; 3.3.x added none — +both lists are written only when non-empty and the edge type is declared only once an edge exists — +so a pre-3.3.0 analysis is refused from `analyzer.version` (wire) / `analyzer_version` (graph) instead, +because `[]` off a 3.2.0 analysis would say "reaches no view" where the truth is that nothing looked. + +Measured on daytrader8 with 3.3.3: 37 edges at level 1–2 (3 `literal`, 34 `table`), 54 at level 4, +19 of 23 JSPs reached; the `TradeConfig.webUI` table's 17 on-disk pages all reached. + +### Changed + +- `codeanalyzer-java` pin `3.2.0` → **`3.3.3`** (the `java` extra and `[tool.backend-versions]`). + 3.3.0 adds the view-template role, `J_DISPATCHES_TO`, and `argument_expr` on `return` body nodes; + 3.3.1 the table tier; 3.3.2 narrows the Jakarta entrypoint finder to lifecycle methods, so + helpers taking servlet-typed parameters are no longer entrypoints and the interprocedural + config-use and view-dispatch tiers bind their parameters (daytrader8 entrypoint marks + 135 → 196: 21 helpers dropped, 82 `init`/`destroy`/`doFilter`/`onMessage` gained); 3.3.3 fixes + the `NullPointerException` 3.3.0–3.3.2 threw on any unbuilt project with a dispatch call, which + this SDK's `test_java_degradation.py` was the first to hit (codeanalyzer-java#265). +- `release/2.0` absorbed `main` at rc.6. + +### Verification + +The Java suite offline on both backends over a1 with the layer injected (edges, suffix filter, +dispatcher resolution, the JSON-only refusal on the graph, the pre-3.3.0 refusal, the empty answer +on a 3.3.x payload that reaches nothing, and the answered-once check across backends); the public +surface pins the three signatures; e2e against the 3.3.3 wheel on daytrader8 at level 1 and 2 +asserts the 37 edges, the 19 views, the three unresolved URLs and the 38 view-template artifacts. + ## [v2.0.0-rc.6] - 2026-09-10 The Java Neo4j backend stops being the lossy one about source text. Until now a graph-backed Java diff --git a/cldk/analysis/java/backend.py b/cldk/analysis/java/backend.py index 9613f9c2..2cace7be 100644 --- a/cldk/analysis/java/backend.py +++ b/cldk/analysis/java/backend.py @@ -109,6 +109,8 @@ JLocalVariable, JMethodDetail, JType, + JViewDispatch, + JViewDispatchUnresolved, ) from cldk.models.java.projections import JCallableOverview, JClassOverview from cldk.utils.exceptions.exceptions import CodeanalyzerExecutionException, CodeanalyzerUsageException, SelectorNotInGraph @@ -154,6 +156,29 @@ "codeanalyzer-java 3.1.0 or newer. get_config_keys() is unaffected: the keys a config artifact declares are read at every generation." ) +#: Why the three view-dispatch accessors refuse on an analysis that predates the pass. +#: codeanalyzer-java 3.3.0 (spec 2026-09-11, codeanalyzer-java#259) added the view-dispatch layer; +#: 3.3.1 (#261) its table tier. Unlike the 3.1.0 trio there is **no unconditional witness** for it: +#: both lists are written only when non-empty, ``J_DISPATCHES_TO`` is declared only once an edge +#: exists, and the release added no always-present key. So this is the one overlay decided from the +#: analyzer generation — ``analyzer.version`` on the wire, ``analyzer_version`` on the ``:JApplication`` +#: anchor — because the alternative, answering ``[]`` off a 3.2.0 analysis, would say "this +#: application reaches no view" where the truth is that nothing looked (D7). +VIEW_DISPATCH_UNAVAILABLE = ( + "the view-dispatch layer cannot be answered for application {app!r}: this analysis was produced by codeanalyzer-java {version}, and the " + "layer (view_dispatches, view_dispatches_unresolved, J_DISPATCHES_TO) exists only from 3.3.0. An empty answer here would say 'this " + "application reaches no view' where the truth is that nothing looked. Re-analyse, or re-emit your Neo4j graph, with codeanalyzer-java " + "3.3.0 or newer. get_artifacts() is unaffected." +) + +#: What the graph backend raises from ``get_unresolved_view_dispatches``: the projection carries no +#: node for a target that resolved to nothing, so the record is reachable from ``analysis.json`` only. +VIEW_DISPATCH_UNRESOLVED_JSON_ONLY = ( + "unresolved view dispatches for application {app!r} are not in the graph: codeanalyzer-java writes view_dispatches_unresolved into " + "analysis.json only (a target that resolved to no artifact has no node to project an edge to), so this backend cannot tell 'every " + "dispatch resolved' from 'the record is elsewhere'. Read them off the local codeanalyzer backend." +) + #: What ``get_external_symbols`` raises on a payload whose run never homed out-of-project call #: targets -- which is not the same fact as a project that calls nothing outside itself (D7). EXTERNAL_SYMBOLS_UNAVAILABLE = ( @@ -1238,6 +1263,102 @@ def get_config_readers(self, key: str) -> List[JCallableOverview]: found[row.key] = row return [JCallableOverview.of(r.key, r.type, r.callable, path=r.path) for r in found.values()] + # -----[ the view-dispatch layer (codeanalyzer-java 3.3.0, python-sdk#404) ]----- + @abstractmethod + def _analyzer_generation(self) -> Tuple[int, int, int] | None: + """The ``(major, minor, patch)`` of the codeanalyzer-java that produced this analysis — + ``analyzer.version`` off the wire, ``analyzer_version`` off the ``:JApplication`` anchor — + or ``None`` when it cannot be read. The one version-shaped probe in this contract, and + :data:`VIEW_DISPATCH_UNAVAILABLE` says why it has to be one.""" + + def _view_overlay(self) -> Tuple[List[JViewDispatch], List[JViewDispatchUnresolved]]: + """This analysis's view-dispatch lists, or raise if the analyzer predates the pass. + + Raises: + CodeanalyzerExecutionException: The analysis was produced by codeanalyzer-java older + than 3.3.0, or by one whose version cannot be read (:data:`VIEW_DISPATCH_UNAVAILABLE`). + """ + generation = self._analyzer_generation() + if generation is None or generation < (3, 3, 0): + version = "unknown" if generation is None else ".".join(map(str, generation)) + raise CodeanalyzerExecutionException(VIEW_DISPATCH_UNAVAILABLE.format(app=self._application_name, version=version)) + app = self.get_application_view() + return list(app.view_dispatches or []), list(app.view_dispatches_unresolved or []) + + def _view_artifact_paths(self) -> Dict[str, str]: + """``artifact id -> repo-relative path`` for every inventoried artifact.""" + return {a.id: path for path, a in self.get_application_view().artifacts.items()} + + @staticmethod + def _view_matches(path: str, view: str) -> bool: + """Segment-aligned suffix match: ``quoteDataPrimitive.jsp`` and + ``src/main/webapp/quoteDataPrimitive.jsp`` both name the same artifact; ``DataPrimitive.jsp`` + names nothing. Never a substring (E8).""" + return path == view or path.endswith("/" + view) + + def get_view_dispatches(self, view: str | None = None) -> List[JViewDispatch]: + """Every view dispatch the analyzer resolved: a body node that hands the request to a view + template, and the artifact it reaches. + + Args: + view: Restrict to one view, matched as a segment-aligned suffix of the artifact's + repo-relative path (``home.jsp``, ``WEB-INF/jsp/home.jsp``, or the whole path). + ``None`` returns every edge. + + Returns: + :class:`~cldk.models.java.models.JViewDispatch`, sorted by ``(src, dst)``. ``prov`` is + the tier that closed the target — see the model's note on ``["table"]``, the one + many-per-site kind. Empty means the pass ran and resolved nothing. + + Raises: + CodeanalyzerExecutionException: See :meth:`_view_overlay`. + """ + dispatches, _ = self._view_overlay() + if view is None: + return dispatches + paths = self._view_artifact_paths() + return [d for d in dispatches if self._view_matches(paths.get(d.dst, ""), view)] + + def get_unresolved_view_dispatches(self) -> List[JViewDispatchUnresolved]: + """Every detected dispatch that closed on no artifact — a variable target, a servlet URL, + a view name matching two templates — kept first class so a page nobody can trace stays as + visible as one that resolves. + + Returns: + :class:`~cldk.models.java.models.JViewDispatchUnresolved`, sorted by + ``(site, reason, target)``; ``prov`` lists every tier attempted. + + Raises: + CodeanalyzerExecutionException: See :meth:`_view_overlay`; and on the Neo4j backend + always (:data:`VIEW_DISPATCH_UNRESOLVED_JSON_ONLY`), because the projection carries + no node for a target that resolved to nothing. + """ + _, unresolved = self._view_overlay() + return unresolved + + def get_view_dispatchers(self, path: str) -> List[JCallableOverview]: + """Overviews of every callable that dispatches to one view — :meth:`get_view_dispatches` + resolved from body nodes back to the callables that own them. + + Args: + path: The view's repo-relative path or any segment-aligned suffix of it, matched as in + :meth:`get_view_dispatches`. + + Returns: + One overview per distinct callable, in the addressing index's order; a callable that + reaches the view from several sites (or through a table's many entries) appears once. + Empty means nothing dispatches to it. + + Raises: + CodeanalyzerExecutionException: See :meth:`_view_overlay`. + """ + found: Dict[str, _Addressed] = {} + for edge in self.get_view_dispatches(path): + row = self._addressing.by_id.get(edge.src.rpartition("@")[0]) + if row is not None: + found[row.key] = row + return [JCallableOverview.of(r.key, r.type, r.callable, path=r.path) for r in found.values()] + # -----[ the type-kind leaf accessors (J-7) ]----- def get_interfaces(self) -> Dict[str, JType]: """Every interface, keyed by qualified name — the subset of :meth:`get_all_classes` whose diff --git a/cldk/analysis/java/codeanalyzer/codeanalyzer.py b/cldk/analysis/java/codeanalyzer/codeanalyzer.py index 71496d6f..c31e78ea 100644 --- a/cldk/analysis/java/codeanalyzer/codeanalyzer.py +++ b/cldk/analysis/java/codeanalyzer/codeanalyzer.py @@ -161,6 +161,14 @@ def _recorded_verdict(verdict_file: Path, analysis_json_file: Path) -> List[Diag return None +def _semver(raw: object) -> Tuple[int, int, int] | None: + """``"3.3.2"`` → ``(3, 3, 2)``; anything that is not three integers is ``None``.""" + parts = str(raw or "").split("-", 1)[0].split(".") + if len(parts) != 3 or not all(p.isdigit() for p in parts): + return None + return int(parts[0]), int(parts[1]), int(parts[2]) + + class JCodeanalyzer(JavaAnalysisBackend): """Build and query the application view of a Java project by invoking codeanalyzer-java. @@ -187,6 +195,10 @@ class JCodeanalyzer(JavaAnalysisBackend): payload occupies the same pipe the log would. """ + def _analyzer_generation(self) -> Tuple[int, int, int] | None: + """``analyzer.version`` off the wire, as a comparable tuple; ``None`` if it is not a semver.""" + return _semver(self.analysis.analyzer.version) + def __init__( self, project_dir: Union[str, Path, None], diff --git a/cldk/analysis/java/java_analysis.py b/cldk/analysis/java/java_analysis.py index 75e3d587..614d5864 100644 --- a/cldk/analysis/java/java_analysis.py +++ b/cldk/analysis/java/java_analysis.py @@ -72,6 +72,8 @@ JField, JMethodDetail, JType, + JViewDispatch, + JViewDispatchUnresolved, ) from cldk.models.java.projections import JCallableOverview, JClassOverview from cldk.models.python import PyArtifact, PyConfigKey, PyConfigRead, PyConfigUseEdge, PyDependency @@ -1949,6 +1951,47 @@ def get_config_readers(self, key: str) -> List[JCallableOverview]: """ return self.backend.get_config_readers(key) + # -----[ the view-dispatch layer (codeanalyzer-java 3.3.0) ]----- + def get_view_dispatches(self, view: str | None = None) -> List[JViewDispatch]: + """Return every resolved view dispatch: which body node hands the request to which view + template (JSP, Facelet, Thymeleaf) — a ``forward`` / ``include`` / ``sendRedirect`` call, a + ``ModelAndView`` construction or ``setViewName``, or a Spring controller's ``return``. + + Args: + view: When given, only edges whose view's repo-relative path ends with it, + segment-aligned (``home.jsp`` or ``WEB-INF/jsp/home.jsp``). + + Raises: + CodeanalyzerExecutionException: The analysis predates codeanalyzer-java 3.3.0, which is + where the pass exists; an older analysis is refused rather than answered ``[]``. + + See Also: + :meth:`get_view_dispatchers`: The same edges, resolved to their dispatching callables. + :meth:`get_unresolved_view_dispatches`: The dispatches this cannot show. + """ + return self.backend.get_view_dispatches(view) + + def get_unresolved_view_dispatches(self) -> List[JViewDispatchUnresolved]: + """Return every detected dispatch that closed on no view — a variable target, a servlet URL, + a view name matching two templates — with its reason and the tiers attempted. + + Raises: + CodeanalyzerExecutionException: The analysis predates codeanalyzer-java 3.3.0; or, on the + Neo4j backend, always — the record lives in ``analysis.json`` only. + """ + return self.backend.get_unresolved_view_dispatches() + + def get_view_dispatchers(self, path: str) -> List[JCallableOverview]: + """Return overviews of every callable that dispatches to the view at ``path``. + + Args: + path: The view's repo-relative path or any segment-aligned suffix of it. + + Raises: + CodeanalyzerExecutionException: As :meth:`get_view_dispatches`. + """ + return self.backend.get_view_dispatchers(path) + # -----[ the type-kind leaf accessors (J-7) ]----- def get_interfaces(self) -> Dict[str, JType]: """Return every interface in the project, keyed by qualified name. diff --git a/cldk/analysis/java/neo4j/neo4j_backend.py b/cldk/analysis/java/neo4j/neo4j_backend.py index c585adf5..103b2cc8 100644 --- a/cldk/analysis/java/neo4j/neo4j_backend.py +++ b/cldk/analysis/java/neo4j/neo4j_backend.py @@ -134,6 +134,7 @@ JavaAnalysisBackend, duplicate_type_name, unhomed_endpoint, + VIEW_DISPATCH_UNRESOLVED_JSON_ONLY, ) from cldk.analysis.java.neo4j import reconstruct as R from cldk.models.java import JGraphEdges @@ -150,6 +151,8 @@ JCompilationUnit, JConfigRead, JConfigUse, + JViewDispatch, + JViewDispatchUnresolved, JDdgEdge, JDecorator, JEntrypointReport, @@ -594,8 +597,36 @@ def _reconstruct(self) -> JApplication: # ``None`` and ``[]`` are different answers here: see :meth:`_overlay_rows`. config_uses=None if report is None else uses, config_reads_unresolved=None if report is None else reads, + # From 3.3.0 the edge is read whatever the application reaches (``[]`` is a real answer); + # before it the key stays ``None`` and the accessors refuse on the generation. The + # unresolved record is JSON-only and never rebuilt here -- see + # :meth:`get_unresolved_view_dispatches`. + view_dispatches=self._view_dispatch_rows() if (self._analyzer_version or (0, 0, 0)) >= (3, 3, 0) else None, ) + def _view_dispatch_rows(self) -> List[JViewDispatch]: + """``J_DISPATCHES_TO`` (codeanalyzer-java 3.3.0): the source is a body node under the id + prefix, the target an artifact reached from the application anchor — the two id spaces meet + on this edge exactly as they do on ``J_USES_CONFIG``.""" + rows = self._run( + "MATCH (:JApplication {id: $app_id})-[:HAS_ARTIFACT]->(a:Artifact)<-[d:J_DISPATCHES_TO]-(src) " + f"WHERE {_scoped('src')} RETURN src.id AS src, a.id AS dst, d.via AS via, d.prov AS prov ORDER BY src.id, a.id", + app_id=self._application_id, + prefix=self._scope_prefix, + ) + return [JViewDispatch(src=r["src"], dst=r["dst"], via=r["via"], prov=list(r["prov"] or [])) for r in rows] + + def _analyzer_generation(self) -> Tuple[int, int, int] | None: + """``analyzer_version`` off the ``:JApplication`` anchor, read once at attach by + :meth:`_probe_schema`.""" + return self._analyzer_version + + def get_unresolved_view_dispatches(self) -> List[JViewDispatchUnresolved]: + """Always raises: the record is JSON-only (:data:`VIEW_DISPATCH_UNRESOLVED_JSON_ONLY`). The + generation check runs first, so a pre-3.3.0 graph gets the more useful of the two reasons.""" + self._view_overlay() + raise CodeanalyzerExecutionException(VIEW_DISPATCH_UNRESOLVED_JSON_ONLY.format(app=self._application_name)) + # ===================================================================================== # The reconstructed view and its index (both built on first use) # ===================================================================================== diff --git a/cldk/models/java/__init__.py b/cldk/models/java/__init__.py index 586be981..9eab3354 100644 --- a/cldk/models/java/__init__.py +++ b/cldk/models/java/__init__.py @@ -29,6 +29,8 @@ JGraphEdges, JImport, JType, + JViewDispatch, + JViewDispatchUnresolved, ) from .projections import JCallableOverview, JClassOverview @@ -46,6 +48,8 @@ "JGraphEdges", "JImport", "JType", + "JViewDispatch", + "JViewDispatchUnresolved", "JCallableOverview", "JClassOverview", "CRUDOperationType", diff --git a/cldk/models/java/models.py b/cldk/models/java/models.py index 9a25a166..35f27b12 100644 --- a/cldk/models/java/models.py +++ b/cldk/models/java/models.py @@ -19,7 +19,8 @@ The wire is one containment tree: ``JAnalysis{analyzer, application}`` → ``JApplication{symbol_table{path → JCompilationUnit}, call_graph, param_in, param_out, artifacts, -dependencies, config_uses, config_reads_unresolved, entrypoint_report}`` → +dependencies, config_uses, config_reads_unresolved, view_dispatches, view_dispatches_unresolved, +entrypoint_report}`` → ``JCompilationUnit{types{name → JType}}`` → ``JType{fields{}, callables{signature → JCallable}, types{}}`` → ``JCallable{body{}, cfg, cdg, ddg, summary, types{}}``. Every node carries a ``can://`` ``id`` and a ``kind``; a unit carries its full ``source`` once and every node's text is a @@ -862,6 +863,44 @@ class JConfigRead(_Base): prov: List[str] = [] +class JViewDispatch(_Base): + """One resolved view dispatch (codeanalyzer-java 3.3.0, spec 2026-09-11 § 4): the body node that + hands the request to a view template and the :class:`JArtifact` it reaches. + + ``src`` is the dispatching body node's id (``@:``) — a + ``RequestDispatcher.forward`` / ``include`` or ``sendRedirect`` call, a ``ModelAndView`` + construction or ``setViewName``, or a Spring controller's ``return``; ``dst`` is the artifact's + ``can:///artifact/`` id. ``via`` names the mechanism (``forward | include | redirect | + view-name | navigation``) and ``prov`` the tier that closed the target: ``["literal"]`` is a string + at the site, ``["dataflow"]`` a local or parameter traced over the L3/L4 substrate — both mean + exactly one target — and ``["table"]`` (3.3.1, § 4.5) a lookup into a static string table, which + is a **may-dispatch**: one edge per entry of the table, from the same site. Kept ``str`` rather + than ``Literal`` on purpose, as :class:`JConfigRead.reason` is: ``navigation`` is reserved and + unemitted today, and a closed type here would break on the analyzer release that fills it.""" + + src: str + dst: str + via: str + prov: List[str] = [] + + +class JViewDispatchUnresolved(_Base): + """A detected dispatch that closed on no artifact — first class, so a page nobody can trace stays + as visible as one that resolves. ``target`` is the decoded literal when there was one and + ``None`` for ``reason="non-literal"``; ``reason`` is ``non-literal`` / ``no-such-artifact`` (a + servlet URL, a ``*.faces`` route, a file outside the repository) / ``ambiguous`` (a view name + matching two templates); ``prov`` lists every tier attempted. ``callee`` is the dispatching + callee's ``@external`` id for a call site and the enclosing callable's id for a ``return`` site. + **JSON-only**: the projection has no node for a target that resolved to nothing.""" + + site: str + callee: str + target: Optional[str] = None + via: str + reason: str + prov: List[str] = [] + + class JApplication(_Base): """The application root. ``call_graph``/``param_in``/``param_out`` are absent below the level that computes them — empty here, never ``None``. @@ -889,6 +928,12 @@ class JApplication(_Base): config_uses: Optional[List[JConfigUse]] = None config_reads_unresolved: Optional[List[JConfigRead]] = None entrypoint_report: Optional[JEntrypointReport] = None + #: The 3.3.0 view-dispatch layer. ``None`` here means only "the key is absent": 3.3.x writes both + #: lists only when non-empty, so — unlike the 3.1.0 trio — no key on the wire is unconditional and + #: the backends decide "predates the pass" from the analyzer generation instead + #: (:data:`~cldk.analysis.java.backend.VIEW_DISPATCH_UNAVAILABLE`). + view_dispatches: Optional[List[JViewDispatch]] = None + view_dispatches_unresolved: Optional[List[JViewDispatchUnresolved]] = None def model_post_init(self, __context: Any) -> None: for path, unit in self.symbol_table.items(): diff --git a/docs/agent-api-reference.md b/docs/agent-api-reference.md index 9fb38c94..e10d132f 100644 --- a/docs/agent-api-reference.md +++ b/docs/agent-api-reference.md @@ -239,8 +239,9 @@ Java-specific facts: accessors** — `get_callables_overview`, `get_method_bodies`, `get_decorated_callables`, `get_callsites_for`, `get_external_symbols`, `get_entrypoints` / `get_entrypoint_classes` / `get_entrypoint_coverage`, `get_artifacts` / `get_dependencies` / `get_config_keys` / -`get_config_uses` / `get_unresolved_config_reads` / `get_config_readers`, and `get_interfaces` / -`get_enums` / `get_enum_members` / `get_records`. Five rules: +`get_config_uses` / `get_unresolved_config_reads` / `get_config_readers`, `get_view_dispatches` / +`get_unresolved_view_dispatches` / `get_view_dispatchers`, and `get_interfaces` / `get_enums` / +`get_enum_members` / `get_records`. Six rules: - **`get_entrypoint_coverage` reads the report from codeanalyzer-java 3.1.0 on.** 3.1.0 (codeanalyzer-java#235) emits the entrypoint pass's own coverage record — `entrypoint_report` on @@ -254,6 +255,19 @@ accessors** — `get_callables_overview`, `get_method_bodies`, `get_decorated_ca count of syntactically-marked callables is not a coverage record. The marks themselves are real and unambiguous — 133 callables and 66 types of daytrader8's 1,216 and 149, 1,501 callables and 904 types of ThingsBoard's — and `get_entrypoints` / `get_entrypoint_classes` return those. +- **`get_view_dispatches` reads codeanalyzer-java 3.3.0's view layer, and is the one accessor + gated on the analyzer generation.** JSP, Facelets and Thymeleaf templates are `:Artifact` nodes + with `roles: ["view-template"]`, and a `J_DISPATCHES_TO` edge (`view_dispatches[]` on the wire) + runs from the body node that hands the request over — a `forward` / `include` / `sendRedirect` + call, a `ModelAndView` construction or `setViewName`, or a Spring controller's `return` — to the + artifact it reaches, with `via` naming the mechanism and `prov` the tier: `literal` and + `dataflow` mean exactly one target, `table` (3.3.1) is a may-dispatch over a static string table, + one edge per entry. `get_view_dispatchers(path)` resolves the sites to their callables; + `get_unresolved_view_dispatches()` is the JSON-only record of what closed on nothing, so the + Neo4j backend refuses it rather than answering `[]`. Unlike the 3.1.0 trio there is no + always-present key to probe, so a pre-3.3.0 analysis is refused from `analyzer.version` / + `analyzer_version`. On daytrader8 with 3.3.3: 37 edges at level 1–2 (3 literal, 34 table), 54 at + level 4, 19 of 23 JSPs reached. - **A marker matches an annotation by simple name.** `get_decorated_callables(["Test"])`, `["@Test"]` and `["org.junit.Test"]` are the same query: the Java wire carries an annotation's simple name, so both sides are compared on the segment after the last `.` with a leading `@` diff --git a/pyproject.toml b/pyproject.toml index 4ef0e17a..c0890b72 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ dependencies = [ # The Neo4j-backed analysis backends (read-only; no analyzer is invoked). neo4j = ["neo4j>=5.14,<7"] # The local Java backend: the analyzer wheel carries the jar and a bundled JVM (jdk4py). -java = ["codeanalyzer-java==3.2.0"] +java = ["codeanalyzer-java==3.3.3"] # Everything. `codeanalyzer-python` and `codeanalyzer-typescript` are still hard # dependencies; #340 moves them here, and this list grows when it does. all = ["cldk[java]", "cldk[neo4j]"] @@ -86,7 +86,7 @@ include = [ ] [tool.backend-versions] -codeanalyzer-java = "3.2.0" +codeanalyzer-java = "3.3.3" codeanalyzer-python = "1.5.2" codeanalyzer-typescript = "1.6.0" diff --git a/tests/analysis/java/test_java_e2e.py b/tests/analysis/java/test_java_e2e.py index 5a75958a..a7048f51 100644 --- a/tests/analysis/java/test_java_e2e.py +++ b/tests/analysis/java/test_java_e2e.py @@ -94,3 +94,24 @@ def test_call_graph_nodes_are_fqn_dot_signature_strings(analysis): # J-8/#8: absolute file lines, sorted — not offsets into ``JCallable.code``, which is a # different string on each backend. assert data["calling_lines"] == sorted(data["calling_lines"]) and all(n > 0 for n in data["calling_lines"]) + + +def test_view_dispatches_reach_daytrader8s_jsps(analysis): + """codeanalyzer-java 3.3.x (python-sdk#404): at level 1 and 2 the literal tier closes 3 sites + and the table tier (3.3.1) 34 more -- every page in ``TradeConfig.webUI`` that exists on disk, + from ``TradeConfigServlet``'s two sites -- so 37 edges reach 19 of daytrader8's 23 JSPs. The + call-graph tier that binds ``TradeServletAction.requestDispatch`` runs at level 4 only, which + these two levels do not reach. Measured off the 3.3.3 jar, not off the SDK.""" + edges = analysis.get_view_dispatches() + assert len(edges) == 37 + assert {(e.via, tuple(e.prov)) for e in edges} == {("forward", ("literal",)), ("include", ("literal",)), ("include", ("table",))} + assert len({e.dst for e in edges}) == 19 + assert [d.key for d in analysis.get_view_dispatchers("PingServlet2Jsp.jsp")] == [ + "com.ibm.websphere.samples.daytrader.web.prims.PingServlet2Jsp.doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)" + ] + unresolved = analysis.get_unresolved_view_dispatches() + assert {u.reason for u in unresolved} == {"no-such-artifact", "non-literal"} + assert {u.target for u in unresolved if u.reason == "no-such-artifact"} == {"welcome.faces", "/servlet/PingServlet2IncludeRcv", "/servlet/PingServlet2ServletRcv"} + views = {p for p, a in analysis.get_artifacts().items() if "view-template" in a.roles} + assert len(views) == 38 and all(p.endswith((".jsp", ".xhtml")) for p in views) + diff --git a/tests/analysis/java/test_java_neo4j_backend.py b/tests/analysis/java/test_java_neo4j_backend.py index 46af282e..e364564b 100644 --- a/tests/analysis/java/test_java_neo4j_backend.py +++ b/tests/analysis/java/test_java_neo4j_backend.py @@ -79,6 +79,8 @@ import pytest +from cldk.utils.exceptions.exceptions import CodeanalyzerExecutionException + logging.getLogger("neo4j").setLevel(logging.ERROR) NEO4J_URI = os.environ.get("CLDK_TEST_NEO4J_URI", "bolt://localhost:7687") @@ -408,6 +410,11 @@ def test_artifact_layer_parity(backends): # ``test_java_entrypoints_live.py`` states that lossiness and pins the counts. assert sorted((u.src, u.dst, tuple(u.prov)) for u in neo.get_config_uses()) == sorted((u.src, u.dst, tuple(u.prov)) for u in ref.get_config_uses()) assert {(r.callee, r.key, r.reason) for r in neo.get_unresolved_config_reads()} == {(r.callee, r.key, r.reason) for r in ref.get_unresolved_config_reads()} + # The 3.3.0 view-dispatch layer: identical resolved edges; the unresolved record is JSON-only, + # which the graph backend states by refusing rather than by an empty list. + assert [(d.src, d.dst, d.via, tuple(d.prov)) for d in neo.get_view_dispatches()] == [(d.src, d.dst, d.via, tuple(d.prov)) for d in ref.get_view_dispatches()] + with pytest.raises(CodeanalyzerExecutionException): + neo.get_unresolved_view_dispatches() # The Java wire's own artifact models carry two fields the shared Py* ones have no home for. assert sorted(neo.application.artifacts) == sorted(ref.application.artifacts) assert {p: (a.text_truncated, a.sha256) for p, a in neo.application.artifacts.items()} == {p: (a.text_truncated, a.sha256) for p, a in ref.application.artifacts.items()} diff --git a/tests/analysis/java/test_java_public_surface.py b/tests/analysis/java/test_java_public_surface.py index 6bfaef2a..ec80182e 100644 --- a/tests/analysis/java/test_java_public_surface.py +++ b/tests/analysis/java/test_java_public_surface.py @@ -105,6 +105,9 @@ "get_config_uses": "(self, key: 'str | None' = None) -> 'List[PyConfigUseEdge]'", "get_unresolved_config_reads": "(self) -> 'List[PyConfigRead]'", "get_config_readers": "(self, key: 'str') -> 'List[JCallableOverview]'", + "get_view_dispatches": "(self, view: 'str | None' = None) -> 'List[JViewDispatch]'", + "get_unresolved_view_dispatches": "(self) -> 'List[JViewDispatchUnresolved]'", + "get_view_dispatchers": "(self, path: 'str') -> 'List[JCallableOverview]'", "get_interfaces": "(self) -> 'Dict[str, JType]'", "get_enums": "(self) -> 'Dict[str, JType]'", "get_enum_members": "(self, qualified_enum_name: 'str') -> 'List[JEnumConstant]'", diff --git a/tests/analysis/java/test_java_view_dispatches.py b/tests/analysis/java/test_java_view_dispatches.py new file mode 100644 index 00000000..43e80b50 --- /dev/null +++ b/tests/analysis/java/test_java_view_dispatches.py @@ -0,0 +1,167 @@ +################################################################################ +# Copyright IBM Corporation 2026 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +################################################################################ +"""The view-dispatch layer (codeanalyzer-java 3.3.0, python-sdk#404) on **both** backends, offline. + +The committed fixtures are 3.1.0 payloads and carry no ``view_dispatches``, so the layer is exercised +over **a1 with the layer injected**: three resolved edges and one unresolved record shaped exactly +as codeanalyzer-java 3.3.3 writes them on daytrader8 (``PingServlet2Jsp.doGet`` forwards to +``PingServlet2Jsp.jsp``; ``PingJDBCRead2JSP.doGet`` includes ``quoteDataPrimitive.jsp``; a forward to +``/servlet/PingServlet2ServletRcv`` is a URL, not a file), re-addressed onto the fixture's own +callable and artifact ids. The second include comes from ``PingServlet2Session2Entity2JSP.doGet``, +the fixture's other ``include`` site — a1 is a 3.1.0 run over 138 units and has no +``PingJDBCWrite2JSP``. The a1 payload as committed is the +*refusal* case: an analysis that predates the pass must not answer ``[]``. +""" +import json +from typing import Dict + +import pytest + +from cldk.analysis.java.backend import JavaAnalysisBackend +from cldk.analysis.java.codeanalyzer.codeanalyzer import JCodeanalyzer +from cldk.analysis.java.neo4j import JNeo4jBackend +from cldk.models.java.models import JViewDispatch, JViewDispatchUnresolved +from cldk.models.java.projections import JCallableOverview +from cldk.utils.exceptions.exceptions import CodeanalyzerExecutionException + +from .test_java_addressing import _graph, _local + +DO_GET = "doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)" + + +def _site(app: dict, unit: str, type_name: str, method_name: str) -> str: + """The ordinal id of the first ``call`` body node invoking ``method_name`` in ``doGet``. The + unit is found by basename: the two include sites live in different ``web/prims`` packages.""" + path = next(k for k in app["symbol_table"] if k.endswith(f"/{unit}.java")) + callable_ = app["symbol_table"][path]["types"][type_name]["callables"][DO_GET] + for local_id, node in callable_["body"].items(): + if node.get("method_name") == method_name: + return f"{callable_['id']}@{local_id}" + raise AssertionError(f"no {method_name} call in {type_name}.doGet") + + +def _with_layer(payload: str) -> str: + doc = json.loads(payload) + app = doc["application"] + doc["analyzer"]["version"] = "3.3.3" + art = {p: a["id"] for p, a in app["artifacts"].items()} + app["view_dispatches"] = sorted( + [ + {"src": _site(app, "PingServlet2Jsp", "PingServlet2Jsp", "forward"), "dst": art["src/main/webapp/PingServlet2Jsp.jsp"], "via": "forward", "prov": ["literal"]}, + {"src": _site(app, "PingJDBCRead2JSP", "PingJDBCRead2JSP", "include"), "dst": art["src/main/webapp/quoteDataPrimitive.jsp"], "via": "include", "prov": ["literal"]}, + {"src": _site(app, "PingServlet2Session2Entity2JSP", "PingServlet2Session2Entity2JSP", "include"), "dst": art["src/main/webapp/quoteDataPrimitive.jsp"], "via": "include", "prov": ["literal"]}, + ], + key=lambda d: (d["src"], d["dst"]), + ) + app["view_dispatches_unresolved"] = [ + { + "site": _site(app, "PingServlet2Servlet", "PingServlet2Servlet", "forward"), + "callee": "can://java/daytrader8/@external/javax.servlet.RequestDispatcher/forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)", + "target": "/servlet/PingServlet2ServletRcv", + "via": "forward", + "reason": "no-such-artifact", + "prov": ["literal"], + } + ] + return json.dumps(doc) + + +def _seed(kind: str, payload: str) -> JavaAnalysisBackend: + backend = (_local if kind == "local" else _graph)(payload) + if kind == "graph": + backend._analyzer_version = (3, 3, 3) + return backend + + +@pytest.fixture(scope="module", params=["local", "graph"]) +def both(request, analysis_json): + return _seed(request.param, _with_layer(analysis_json)) + + +@pytest.fixture(scope="module", params=["local", "graph"]) +def both_before(request, analysis_json): + """a1 as committed: codeanalyzer-java 3.1.0, no view-dispatch pass.""" + backend = (_local if request.param == "local" else _graph)(analysis_json) + if request.param == "graph": + backend._analyzer_version = (3, 1, 0) + return backend + + +def test_get_view_dispatches_carries_the_edges_and_their_mechanism(both): + edges = both.get_view_dispatches() + assert len(edges) == 3 and all(isinstance(e, JViewDispatch) for e in edges) + assert [(e.via, tuple(e.prov)) for e in edges] == [("include", ("literal",)), ("include", ("literal",)), ("forward", ("literal",))] or sorted((e.via, tuple(e.prov)) for e in edges) == [("forward", ("literal",)), ("include", ("literal",)), ("include", ("literal",))] + assert all(e.src.startswith(e.src.rpartition("@")[0] + "@") for e in edges), "src is a body-node id" + assert {e.dst.rsplit("/", 1)[1] for e in edges} == {"PingServlet2Jsp.jsp", "quoteDataPrimitive.jsp"} + assert [(e.src, e.dst) for e in edges] == sorted((e.src, e.dst) for e in edges), "sorted by (src, dst)" + + +def test_get_view_dispatches_filters_by_the_views_path_suffix(both): + two = both.get_view_dispatches("quoteDataPrimitive.jsp") + assert len(two) == 2 and all(e.dst.endswith("/quoteDataPrimitive.jsp") for e in two) + assert len(both.get_view_dispatches("src/main/webapp/quoteDataPrimitive.jsp")) == 2, "a longer suffix still matches" + assert both.get_view_dispatches("DataPrimitive.jsp") == [], "segment-aligned, never a substring" + assert both.get_view_dispatches("no/such.jsp") == [] + + +def test_get_view_dispatchers_resolves_the_sites_to_their_callables(both): + dispatchers = both.get_view_dispatchers("quoteDataPrimitive.jsp") + assert all(isinstance(d, JCallableOverview) for d in dispatchers) + assert sorted(d.key for d in dispatchers) == [ + f"com.ibm.websphere.samples.daytrader.web.prims.PingJDBCRead2JSP.{DO_GET}", + f"com.ibm.websphere.samples.daytrader.web.prims.ejb3.PingServlet2Session2Entity2JSP.{DO_GET}", + ] + assert [d.key for d in both.get_view_dispatchers("PingServlet2Jsp.jsp")] == [f"com.ibm.websphere.samples.daytrader.web.prims.PingServlet2Jsp.{DO_GET}"] + assert both.get_view_dispatchers("no/such.jsp") == [] + + +def test_get_unresolved_view_dispatches_keeps_the_url_visible_on_the_local_backend(both): + if isinstance(both, JNeo4jBackend): + # JSON-only: the projection has no node for a target that resolved to nothing, so the + # graph backend refuses rather than answering the ambiguous empty. + with pytest.raises(CodeanalyzerExecutionException, match="analysis.json"): + both.get_unresolved_view_dispatches() + return + unresolved = both.get_unresolved_view_dispatches() + assert len(unresolved) == 1 and isinstance(unresolved[0], JViewDispatchUnresolved) + u = unresolved[0] + assert (u.via, u.reason, u.target, u.prov) == ("forward", "no-such-artifact", "/servlet/PingServlet2ServletRcv", ["literal"]) + assert u.site.startswith(u.site.rpartition("@")[0] + "@") + + +def test_a_payload_without_the_pass_refuses_rather_than_answering_empty(both_before): + for call in (both_before.get_view_dispatches, both_before.get_unresolved_view_dispatches, lambda: both_before.get_view_dispatchers("x.jsp")): + with pytest.raises(CodeanalyzerExecutionException, match="3.3.0"): + call() + + +def test_a_newer_payload_with_no_dispatches_answers_empty(analysis_json): + doc = json.loads(analysis_json) + doc["analyzer"]["version"] = "3.3.3" + local = _local(json.dumps(doc)) + assert local.get_view_dispatches() == [] and local.get_unresolved_view_dispatches() == [] + assert local.get_view_dispatchers("x.jsp") == [] + + +def test_the_layer_is_answered_once_for_both_backends(): + """One implementation on the contract for the two edge accessors; the graph backend overrides + only the unresolved one, to refuse what the projection does not carry.""" + for name in ("get_view_dispatches", "get_view_dispatchers"): + shared = getattr(JavaAnalysisBackend, name) + for backend in (JCodeanalyzer, JNeo4jBackend): + assert getattr(backend, name) is shared, f"{backend.__name__} overrides {name}" + assert JCodeanalyzer.get_unresolved_view_dispatches is JavaAnalysisBackend.get_unresolved_view_dispatches + assert JNeo4jBackend.get_unresolved_view_dispatches is not JavaAnalysisBackend.get_unresolved_view_dispatches diff --git a/uv.lock b/uv.lock index fb3df067..beda8a04 100644 --- a/uv.lock +++ b/uv.lock @@ -300,7 +300,7 @@ wheels = [ [[package]] name = "cldk" -version = "2.0.0rc6" +version = "2.0.0rc7" source = { editable = "." } dependencies = [ { name = "codeanalyzer-python" }, @@ -350,7 +350,7 @@ test = [ requires-dist = [ { name = "cldk", extras = ["java"], marker = "extra == 'all'" }, { name = "cldk", extras = ["neo4j"], marker = "extra == 'all'" }, - { name = "codeanalyzer-java", marker = "extra == 'java'", specifier = "==3.2.0" }, + { name = "codeanalyzer-java", marker = "extra == 'java'", specifier = "==3.3.3" }, { name = "codeanalyzer-python", specifier = "==1.5.2" }, { name = "codeanalyzer-typescript", specifier = "==1.6.0" }, { name = "neo4j", marker = "extra == 'neo4j'", specifier = ">=5.14,<7" }, @@ -398,13 +398,13 @@ wheels = [ [[package]] name = "codeanalyzer-java" -version = "3.2.0" +version = "3.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jdk4py" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/06/26d6c653ada36ce11358b08a33bbc24ca8b6f0da8b843c379c6d160691a3/codeanalyzer_java-3.2.0-py3-none-any.whl", hash = "sha256:c4e98c22c719bdb1665e98d8bcee4e2d81cc18ec518f66e467d77bdd6d871251", size = 32840590, upload-time = "2026-09-10T15:14:49.099Z" }, + { url = "https://files.pythonhosted.org/packages/28/34/8364c6d79ee9ad3e3ef40dae0f95de30db0a9e43cc1032b351586c3a5912/codeanalyzer_java-3.3.3-py3-none-any.whl", hash = "sha256:0a499ada8bba00ac4adf45786e4bb578052af17e295796367afc951f20a0d84b", size = 32863677, upload-time = "2026-09-11T16:09:16.097Z" }, ] [[package]] From 4a11011bef5d8ff358f7a0a7bfb1918b34ef8e69 Mon Sep 17 00:00:00 2001 From: Rahul Krishna Date: Fri, 11 Sep 2026 12:13:24 -0400 Subject: [PATCH 7/7] chore(release): 2.0.0-rc.7 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c0890b72..d489d08f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "cldk" -version = "2.0.0-rc.6" +version = "2.0.0-rc.7" description = "The official Python SDK for Codellm-Devkit." readme = "README.md" license = { text = "Apache-2.0" }